简单数谜 (caioj1044)

来源:互联网 发布:win7旗舰版打不开软件 编辑:程序博客网 时间:2024/05/24 06:39

题目见: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;       //行的现有数据的和 +ilz[y] += i;       //列的现有数据的和 +idfs(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;} 


原创粉丝点击