【蓝桥杯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 }

猜你喜欢

转载自www.cnblogs.com/Aikoin/p/10584673.html