【藍橋杯2016_C++】t3:方格填數

如下的10個格子

填入0~9的數字。要求:連續的兩個數字不能相鄰。
(左右、上下、對角都算相鄰)

一共有多少種可能的填數方案?

請填寫表示方案數目的整數。

法一

全排列+check,可以把這個格子當成一個存放0~9的一維數組再進行全排列,把每種不符合要求的條件都列出來check一下:

 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
 5 int ans = 0;
 6 bool check(){
 7     if(abs(a[0]-a[1])==1 || abs(a[0]-a[3])==1 || abs(a[0]-a[4])==1 || abs(a[0]-a[5])==1
 8     || abs(a[1]-a[2])==1 || abs(a[1]-a[4])==1 || abs(a[1]-a[5])==1 || abs(a[1]-a[6])==1
 9     || abs(a[2]-a[5])==1 || abs(a[2]-a[6])==1
10     || abs(a[3]-a[4])==1 || abs(a[3]-a[7])==1 || abs(a[3]-a[8])==1
11     || abs(a[4]-a[5])==1 || abs(a[4]-a[7])==1 || abs(a[4]-a[8])==1 || abs(a[4]-a[9])==1
12     || abs(a[5]-a[6])==1 || abs(a[5]-a[8])==1 || abs(a[5]-a[9])==1
13     || abs(a[6]-a[9])==1
14     || abs(a[7]-a[8])==1
15     || abs(a[8]-a[9])==1
16     ) return false;
17     else{
18         ans++;
19         return true;    
20     }
21 }
22 int main()
23 {
24     do{
25         check();
26     }while(next_permutation(a,a+10));    
27     cout<<ans;
28     return 0;
29 }

有一個手動實現全排列的模板:

 1 /*考慮第k個位置,一般從0開始*/
 2 void f(int k) {
 3 //出口
 4     if (k == 10) {
 5         bool b = check();
 6         if(b)
 7             ans++;
 8         return;
 9     }
10 
11 
12     for (int i = k; i < 10; ++i) {
13         //嘗試將位置i與位置k交換,以此確定k位的值
14         {
15             int t = a[i];
16             a[i] = a[k];
17             a[k] = t;
18         }
19         f(k + 1);
20 //        回溯
21         {
22             int t = a[i];
23             a[i] = a[k];
24             a[k] = t;
25         }
26 
27     }
28 }

法二

check列出來可能很亂,還有一種方法,就是把方格擴展成5*6的二維數組,先把所有格子都初始化爲-10(除了-1,其他負數比如-5、-7都可):

check改爲把每個元素和它周圍一圈的元素做差取絕對值判斷,寫起來就簡潔很多。擴展方格是爲了防止check時下標越界。

從第一個格子(1,2)開始,從0~9中選一個沒有被標記過的填進去,然後把填進去的數標記成已訪問;然後check提前剪枝,滿足條件就下一層遞歸,否則格子恢復-10的值並continue。最後還要回溯,標記清零。

這種方法每填一個格子就會提前check剪枝,不像法一,全部排列完才進行判斷,提高了效率。

 1 #include <iostream>
 2 #include <algorithm>
 3 using namespace std;
 4 int a[5][6];
 5 int vis[10];
 6 int ans = 0;
 7 void init(){
 8     for(int i=0;i<5;i++)
 9         for(int j=0;j<6;j++)
10             a[i][j] = -10;
11 }
12 bool check(int x,int y){
13     for(int i = x-1;i<=x+1;i++)
14         for(int j = y-1;j<=y+1;j++)
15             if(abs(a[x][y]-a[i][j])==1) return false;
16     return true;
17 }
18 void f(int x,int y){
19     if(x==3 && y==4){  //如果已經填完了最後一個格子 
20         ans++;
21         return;
22     }
23     for(int i = 0;i<10;i++){
24         if(vis[i]==0){  //從0~9選一個沒有填過的數字 
25             a[x][y] = i;
26             if(!check(x,y)){ //如果不滿足check條件 
27                 a[x][y] = -10;  //恢復並continue 
28                 continue;
29             }
30             vis[i] = 1; //滿足條件,標記並繼續填下一個格子 
31             if(y==4) f(x+1,1);  //換行 
32             else f(x,y+1); //繼續填右側格子 
33             //回溯
34             vis[i] = 0;
35             a[x][y] = -10; 
36         }
37     }
38 }
39 int main()
40 {
41     init();
42     f(1,2);
43     cout<<ans<<endl;     
44     return 0;
45 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章