题目见:http://www.caioj.cn/problem.php?id=1044
不想写具体思路,其实就是按行搜索逐渐往下,直至所有n*m个格子都放置了合适的数。搜时适时加必要的剪枝。
/*caioj.1044
很多人都曾经听说过数独,但你是否听说过数谜(Karuro)呢?实际上,数谜是数独的更大(且更难)
的兄弟问题,而且在日本也是非常受欢迎的。数谜问题和填字游戏类似,不过它要填的不是文字而是数
字。数谜游戏的目标是用1-9填满所有空格,且这些数字相加的和满足相应的要求(或者称为“提示”)
,且在同一栏(“栏”是指一些水平或者竖直的连续的空格,用于提示的格子不算空格)不能填重复的
数字。当所有格子按要求被填满后,这个数谜就看作被解决了。图1和图2是一个可能的数谜游戏示例。
*/
/*caioj.1044 很多人都曾经听说过数独,但你是否听说过数谜(Karuro)呢?实际上,数谜是数独的更大(且更难) 的兄弟问题,而且在日本也是非常受欢迎的。数谜问题和填字游戏类似,不过它要填的不是文字而是数 字。数谜游戏的目标是用1-9填满所有空格,且这些数字相加的和满足相应的要求(或者称为“提示”) ,且在同一栏(“栏”是指一些水平或者竖直的连续的空格,用于提示的格子不算空格)不能填重复的 数字。当所有格子按要求被填满后,这个数谜就看作被解决了。图1和图2是一个可能的数谜游戏示例。 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; int t,n,m,ansx; int H[12],L[12];//存每一行的要求和值和列值 int hz[12],lz[12];//记录每一行的实时和值与没一列的实时列值 int ans[15][15],map[15][15]; //ans存储第一个答案地图,zt存搜索过程中的实时地图 bool h[15][15],l[15][15]; //一行内1-9或列内1-9是否用过 void initRead(){ scanf("%d%d",&n,&m); ansx = 0; memset(ans,0,sizeof(ans)); memset(h,false,sizeof(h)); memset(l,false,sizeof(l)); memset(hz,0,sizeof(hz)); memset(lz,0,sizeof(lz)); memset(map,0,sizeof(map)); for(int i = 1; i<= n; i++) scanf("%d",&H[i]); for(int i = 1; i<= m; i++) scanf("%d",&L[i]); for(int i = 1; i<= n; i++){ for(int j = 1;j<= m; j++){ scanf("%d",&map[i][j]); h[i][map[i][j]] = true; //第i行已用掉map[i][j] ; l[j][map[i][j]] = true; //第j列已用掉map[i][j]; hz[i] += map[i][j]; //第i行和值累加map[i][j] lz[j] += map[i][j]; //第j行和值累加map[i][j]; } } } void dfs(int x,int y){ if(ansx >1) return; //有多于等于2个答案时不用继续,因为不用对更多的答案计数或输出。 if(x > n){ bool flag = true; //因为是一行行满足行值和的前提下开始下一行的搜索的。 //因此在每行能填完,当填到第n+1行时只需判断列上是否满足列值和值是指定值 for(int i = 1;i<= m ;i++) if(lz[i] != L[i]) { flag = false; break; } if(flag){ ansx++; if(ansx==1){ //如果是第一个方案,就记下正解 for(int i = 1;i<= n; i++){ for(int j = 1;j<=m ; j++){ ans[i][j] = map[i][j]; } } } } } else if(y > m){ //一行填完 时 if(hz[x] == H[x]) dfs(x+1,1); } else if(map[x][y] != 0) dfs(x,y+1); //如果当前搜到的点有值,则搜本行下一个 else{ for(int i = 1;i<= 9 ;i++){ //如果该数在第x行和第y列没有被用过且放入i后不会超过行和值和列和值 if(!h[x][i] && !l[y][i] && hz[x]+i<=H[x] && lz[y]+i<= L[y]) { h[x][i] = true; //标记i该数在第x行已用 l[y][i] = true; //标记i该数在第y行已用 map[x][y] = i; //记入地图 hz[x] += i; //行的现有数据的和 +i lz[y] += i; //列的现有数据的和 +i dfs(x,y+1); h[x][i] = false; //标记i该数在第x行未用 l[y][i] = false; //标记i该数在第y行未用 map[x][y] = 0; //从地图中清除 hz[x] -= i; //行的现有数据的和 lz[y] -= i; //列的现有数据的和 } } } } int main(){ freopen("1044.in","r",stdin) ; freopen("1044.out","w",stdout); scanf("%d",&t); while(t--){ initRead(); dfs(1,1); if(ansx == 1) { for(int i = 1;i<= n;i++){ for(int j = 1;j< m;j++){ printf("%d ",ans[i][j]); } printf("%d\n",ans[i][m]); } } else if(ansx > 1) printf("Not unique.\n"); else printf("No answer.\n"); } return 0; }