Description
很多人都曾经听说过数独,但你是否听说过数谜(Karuro)呢?实际上,数谜是数独的更大(且更难)的兄弟问题,而且在日本也是非常受欢迎的。
数谜问题和填字游戏类似,不过它要填的不是文字而是数字。数谜游戏的目标是用1-9填满所有空格,且这些数字相加的和满足相应的要求(或者称为“提示”),且在同一栏(“栏”是指一些水平或者竖直的连续的空格,用于提示的格子不算空格)不能填重复的数字。当所有格子按要求被填满后,这个数谜就看作被解决了。图1和图2是一个可能的数谜游戏示例。
当然,直接求解数谜问题的话会比较困难。所以现在我们需要解决的是一个更简单的数谜问题。简单数谜的形状是一个(n+1)行乘(m+1)列的矩形。而简单数谜也只有两种要求,就是行要求和列要求,且分别处于第一行和第一列,其他格子则是空格,而左上角是忽略不计的。coolzzz同学爱好简单数谜,他已经给一些简单数谜填好了其中的一些空格。现在,他想寻求你的帮助,来帮他完成这些简单数谜。如图3所示,2和9是coolzzz同学已经填好的空格,图4则是一个基于图3 的一个可能的解答。
Input
输入包含多组测试数据。第一行包含一个正整数T,表示测试数据数目。每组数据第一行是n(n<10)和m(m<10),表示数谜的形状的大小。接下来一行有n个整数,是相应的行要求;然后一行是m个整数,是相应的列要求。接下来的n行每行有m个小于10的非负整数,0表示该空格还没有被填数字,其他表示coolzzz同学已经填好的数字。输入数据保证未填数字的空格不会超过16个。
Output
对于每组测试数据,输出若干行。如果基于coolzzz已填的结果,该数谜只有一个解,则输出该解;如果不止一个解,则输出一行“Not unique.”;如果没有解,则输出一行“No answer.”。
Sample Input
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
3 3 3 6 6 6 6 6 6 0 0 0 0 3 0 0 0 0 2 3 10 17 5 16 6 2 0 0 0 9 0 2 2 3 5 4 4 0 0 0 0 |
Sample Output
1 2 3 4 5 |
Not unique. 2 7 1 3 9 5 No answer. |
题解
一道简单的爆搜题,和数独比起来稍微复杂一点(然而代码量更少),比较坑爹的就是如果不加一句话的话全部超时,加上去了就只要32ms
我们每次填只关心当前行满不满足要求,最后结束的时候再来判断是不是合法
具体数组作用可以用一个表格体现
数组(变量)名称 | 数组(变量)作用 |
---|---|
ans | 用来存放最终的结果 |
num | 用来统计有多少个答案 |
kakuro | 初始状态以及之后搜索时的状态 |
x,y | 要求的行、列和 |
X,Y | 当前行、列有哪些数是用过的 |
val_x,val_y | 当前状态的行、列和 |
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXN=15; int num; int ans[MAXN][MAXN],kakuro[MAXN][MAXN]; int x[MAXN],y[MAXN]; bool Y[MAXN][MAXN],X[MAXN][MAXN]; int val_x[MAXN],val_y[MAXN]; int n,m; inline void init(){ cin>>n>>m; num=0; memset(ans,0,sizeof(ans)); memset(kakuro,0,sizeof(kakuro)); memset(val_x,0,sizeof(val_x)); memset(val_y,0,sizeof(val_y)); memset(X,0,sizeof(X)); memset(Y,0,sizeof(Y)); for(int i=1;i<=n;i++)cin>>y[i]; for(int j=1;j<=m;j++)cin>>x[j]; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ scanf("%d",&kakuro[i][j]); Y[i][kakuro[i][j]]=1; X[j][kakuro[i][j]]=1; val_y[i]+=kakuro[i][j]; val_x[j]+=kakuro[i][j]; } } } inline void dfs(int now_x,int now_y){ if(num>=2)return; if(now_y>n){ bool ok=1; for(int i=1;i<=m;i++){ if(val_x[i]!=x[i]){ ok=0; break; } } if(ok){ num++; memcpy(ans,kakuro,sizeof(kakuro)); } } else if (now_x > m) { if (val_y[now_y] == y[now_y]) {//不加全超时 dfs(1, now_y + 1); } } else if(kakuro[now_y][now_x]!=0)dfs(now_x+1,now_y); else { for(int i=1;i<=9;i++){ if(!Y[now_y][i]&&!X[now_x][i]&&val_x[now_x]+i<=x[now_x]&&val_y[now_y]+i<=y[now_y]){ Y[now_y][i]=X[now_x][i]=1; val_x[now_x]+=i; val_y[now_y]+=i; kakuro[now_y][now_x]=i; dfs(now_x+1,now_y); Y[now_y][i]=X[now_x][i]=0; val_x[now_x]-=i; val_y[now_y]-=i; kakuro[now_y][now_x]=0; } } } } inline void out(){ if(num==0)printf("No answer.\n"); else if(num==1){ for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ printf("%d ",ans[i][j]); } printf("\n"); } } else { printf("Not unique.\n"); } } int main(){ // freopen("poi.out","w",stdout); int t; cin>>t; int T=t; while(t--){ // printf("Case %d:\n",T-t); init(); dfs(1,1); out(); } return 0; } |