軟考常用算法設(shè)計方法(一)(4)

字號:

【問題】 填字游戲
    問題描述:在3×3個方格的方陣中要填入數(shù)字1到n(n≥10)內(nèi)的某9個數(shù)字,每個方格填一個整數(shù),似的所有相鄰兩個方格內(nèi)的兩個整數(shù)之和為質(zhì)數(shù)。試求出所有滿足這個要求的各種數(shù)字填法。
    可用試探發(fā)找到問題的解,即從第一個方格開始,為當(dāng)前方格尋找一個合理的整數(shù)填入,并在當(dāng)前位置正確填入后,為下一方格尋找可填入的合理整數(shù)。如不能為當(dāng)前方格找到一個合理的可填證書,就要回退到前一方格,調(diào)整前一方格的填入數(shù)。當(dāng)?shù)诰艂€方格也填入合理的整數(shù)后,就找到了一個解,將該解輸出,并調(diào)整第九個的填入的整數(shù),尋找下一個解。
    為找到一個滿足要求的9個數(shù)的填法,從還未填一個數(shù)開始,按某種順序(如從小到大的順序)每次在當(dāng)前位置填入一個整數(shù),然后檢查當(dāng)前填入的整數(shù)是否能滿足要求。在滿足要求的情況下,繼續(xù)用同樣的方法為下一方格填入整數(shù)。如果最近填入的整數(shù)不能滿足要求,就改變填入的整數(shù)。如對當(dāng)前方格試盡所有可能的整數(shù),都不能滿足要求,就得回退到前一方格,并調(diào)整前一方格填入的整數(shù)。如此重復(fù)執(zhí)行擴展、檢查或調(diào)整、檢查,直到找到一個滿足問題要求的解,將解輸出。
    回溯法找一個解的算法:
    { int m=0,ok=1;
     int n=8;
     do{
     if (ok) 擴展;
     else 調(diào)整;
     ok=檢查前m個整數(shù)填放的合理性;
     } while ((!ok||m!=n)&&(m!=0))
     if (m!=0) 輸出解;
     else 輸出無解報告;
    }
    如果程序要找全部解,則在將找到的解輸出后,應(yīng)繼續(xù)調(diào)整最后位置上填放的整數(shù),試圖去找下一個解。相應(yīng)的算法如下:
    回溯法找全部解的算法:
    { int m=0,ok=1;
     int n=8;
     do{
     if (ok)
    { if (m==n)
    { 輸出解;
    調(diào)整;
    }
    else 擴展;
     }
     else 調(diào)整;
     ok=檢查前m個整數(shù)填放的合理性;
     } while (m!=0);
    }
    為了確保程序能夠終止,調(diào)整時必須保證曾被放棄過的填數(shù)序列不會再次實驗,即要求按某種有許模型生成填數(shù)序列。給解的候選者設(shè)定一個被檢驗的順序,按這個順序逐一形成候選者并檢驗。從小到大或從大到小,都是可以采用的方法。如擴展時,先在新位置填入整數(shù)1,調(diào)整時,找當(dāng)前候選解中下一個還未被使用過的整數(shù)。將上述擴展、調(diào)整、檢驗都編寫成程序,細節(jié)見以下找全部解的程序。
    【程序】
    # include
    # define n 12
    void write(int a[ ])
    { int i,j;
     for (i=0;i<3;i++)
     { for (j=0;j<3;j++)
     printf(“%3d”,a[3*i+j]);
     printf(“\n”);
     }
     scanf(“%*c”);
    }
    int b[n+1];
    int a[10];
    int isprime(int m)
    { int i;
     int primes[ ]={2,3,5,7,11,17,19,23,29,-1};
     if (m==1||m%2=0) return 0;
     for (i=0;primes[i]>0;i++)
     if (m==primes[i]) return 1;
     for (i=3;i*i<=m;)
     { if (m%i==0) return 0;
     i+=2;
     }
     return 1;
    }