1160: 方格填数
时间限制: 1 Sec 内存限制: 128 MB提交: 5 解决: 3
[提交][状态][讨论版]
题目描述
如上面的10个格子,填入0~9的数字,不能重复(原先已经填了一部分数字),要求:连续的两个数字不能相邻(左右,上下,对角都算相邻)。例如:数字0和1不能放在一起。
问:一共有多少种可能的填数方案?
输入
输入多组测试数据。
每组测试数据有三行,第一行三个整数,第二行四个整数,第三行三个整数,之间用空格隔开,分别代表每个空格所填的数,如果原先没有数,则填-1。
输入数据保证不重复数字,不保证连续数字不相邻。
输出
每组测试数据输出一行。
输出表示方案数目的整数。
样例输入
-1 -1 -1
-1 -1 -1 -1
-1 -1 -1
0 1 -1
-1 -1 -1 -1
-1 -1 -1
1 3 5
-1 -1 -1 -1
-1 -1 -1
样例输出
1580
0
8
**模块话思想在复杂问题中作用明显
代码长,好多地方写的效率很低,也懒得再改了,刚好能过就行
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int map[3][4];// 存储 int NEXT[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};// 用于判断八个方向 bool num[10]; int count; bool isright;//判断输入的数据是否正确 bool check(int x,int y,int n)//检查八个方向是否有重复 { int i,tx,ty; for(i=0;i<8;i++) { tx = x+NEXT[i][0]; ty = y+NEXT[i][1]; if(tx>=0&&tx<3 && ty>=0&&ty<4) { if(map[tx][ty]!=-5 && (map[tx][ty] == n+1 || map[tx][ty] == n-1))//如果相差为 1 则返回false return false; else continue; } } return true; } bool Write()//读入函数 { int i; memset(num,0,sizeof(num));//读入前清空标记 for(i=1;i<4;i++)//读入第一行,从第二个数字开始的 { if(scanf("%d",&map[0][i])!=EOF) { if(map[0][i]==-1)//这里把-1变成-5是应为 0 和 -1 也是相邻的, map[0][i]=-5; else num[map[0][i]] = true;//如果读入数据,就把数字标记 } else return false; } for(i=0;i<4;i++)//读入第二行 { scanf("%d",&map[1][i]); if(map[1][i]==-1) //同理如上 map[1][i]=-5; else num[map[1][i]] = true; } for(i=0;i<3;i++) { scanf("%d",&map[2][i]); if(map[2][i]==-1) //同理如上 map[2][i]=-5; else num[map[2][i]] = true; } return true; } void dfs(int x)//搜索 { int r,c,i; if(x==11)//出口 { count++; return; } r = x/4;//将点转换为坐标,思路来自八皇后 c = x%4; if(map[r][c]==-5)//如果==-5 表示我们标记为 空(未填数字) { for(i=0;i<=9;i++) { if(num[i]==false && check(r,c,i)==true)//1,数字i未被使用,2,(r,c)的八个方向与i的值比较 { num[i] = true;//标记 map[r][c] = i; dfs(x+1); num[i] = false;//去除标记 map[r][c] = -5;//!!!一定要把这个位置给复原(-5表示未填数字),我就在这个小问题上卡了进一小时,调试半天, } } }else dfs(x+1);//如果当前位置有数字了,就直接跳过 } void check2()//这个check函数用于判断用户输入的结果是否有相邻的值 { int i,r,c; for(i=1;i<=11;i++)//模拟搜索,从头看到位, { r=i/4; c=i%4; if(map[r][c]!=-5) { if(check(r,c,map[r][c])==false)//如果不满足 { isright = false;//改变我们定义的全局标记 return; } else continue; } } } int main() { while(Write()==true) { map[0][0] = map[2][3] = -5;//把两个角落的值给初始化一样,避免意外(默认初始值为0,就有可能和 0 1 ,相邻) isright = true; check2();//检查用户输入 if(isright==true)//如果检查正确 { count = 0; dfs(1); cout<<count<<endl; }else//不正确直接输出0就好 cout<<"0"<<endl; } return 0; }
下面是纯代码
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int map[3][4]; int next[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}}; bool num[10]; int count; bool isright; bool check(int x,int y,int n) { int i,tx,ty; for(i=0;i<8;i++) { tx = x+next[i][0]; ty = y+next[i][1]; if(tx>=0&&tx<3 && ty>=0&&ty<4) { if(map[tx][ty]!=-5 && (map[tx][ty] == n+1 || map[tx][ty] == n-1)) return false; else continue; } } return true; } bool Write() { int i; memset(num,0,sizeof(num)); for(i=1;i<4;i++) { if(scanf("%d",&map[0][i])!=EOF) { if(map[0][i]==-1) map[0][i]=-5; else num[map[0][i]] = true; } else return false; } for(i=0;i<4;i++) { scanf("%d",&map[1][i]); if(map[1][i]==-1) map[1][i]=-5; else num[map[1][i]] = true; } for(i=0;i<3;i++) { scanf("%d",&map[2][i]); if(map[2][i]==-1) map[2][i]=-5; else num[map[2][i]] = true; } return true; } void dfs(int x) { int r,c,i; if(x==11) { count++; return; } r = x/4; c = x%4; if(map[r][c]==-5) { for(i=0;i<=9;i++) { if(num[i]==false && check(r,c,i)==true) { num[i] = true; map[r][c] = i; dfs(x+1); map[r][c] = -5; num[i] = false; } } }else dfs(x+1); } void check2() { int i,r,c; for(i=1;i<=11;i++) { r=i/4; c=i%4; if(map[r][c]!=-5) { if(check(r,c,map[r][c])==false) { isright = false; return; } else continue; } } } int main() { while(Write()==true) { map[0][0] = map[2][3] = -5; isright = true; check2(); if(isright==true) { count = 0; dfs(1); cout<<count<<endl; }else cout<<"0"<<endl; } return 0; }