poj 3074 Sudoku (精确覆盖,DLX,搜索)
来源:互联网 发布:许知远 陈嘉映 知乎 编辑:程序博客网 时间:2024/05/01 16:59
题意:一个9*9的数独,实现给你一些放好的数,且保证答案只有一种,让你输出答案。
思路:这题可以采用精确覆盖的DLX做法。首先对于数独而言,每个格子有9种情况,且有9*9 个格子,所以可以让行等于9*9*9。然后再看数独的限制条件,每个数字在每一行,每一列,每一个3*3的区域中只能出现一次。因此根据精确覆盖的特性,每一个元素只能被覆盖一次,可以设列为9行每行个,9列每行9个,9个小区域每行9个,且81个格子放一个,即(9+9+9)*9+81列,所以元素为(729)*(4*9*9)个。接下来直接使用DLX,注意的是对于每个元素设个X数组,值为当前元素所在行,便于输出。
代码如下:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#define inf 0x3f3f3f3f//最大值#include <algorithm>using namespace std;const int maxnn=250000;const int N=9;const int maxr=N*N*N+10;const int maxc=N*N*4+10;char map[maxr];int size;int x[maxnn];int v[maxr];struct node{ int u,d,l,r; int s,p;};node dlx[maxnn];//十字链表int head;int h[maxr];//行头int q[100];//答案集合,存储当前元素void init(int r,int c)//初始化{ head=0; for(int i=0; i<=c; i++) { dlx[i].s=0; dlx[i].u=i; dlx[i].d=i; dlx[i].r=i+1; dlx[i+1].l=i; } size=c; dlx[c].r=0; while(r) { h[r--]=-1; }}void remove(int c){ dlx[dlx[c].r].l=dlx[c].l; dlx[dlx[c].l].r=dlx[c].r; for(int i=dlx[c].d; i!=c; i=dlx[i].d) for(int j=dlx[i].r; j!=i; j=dlx[j].r) { dlx[dlx[j].d].u=dlx[j].u; dlx[dlx[j].u].d=dlx[j].d; dlx[dlx[j].p].s--; }}void resume(int c){ for(int i=dlx[c].u; i!=c; i=dlx[i].u) for(int j=dlx[i].l; j!=i; j=dlx[j].l) { dlx[dlx[j].u].d=j; dlx[dlx[j].d].u=j; dlx[dlx[j].p].s++; } dlx[dlx[c].r].l=dlx[dlx[c].l].r=c;}bool dfs_dlx(int k)//DLX{ if(dlx[head].r==head) { for(int i=0; i<k; i++) { map[(x[q[i]]-1)/9+1]=(x[q[i]]-1)%9+1+'0'; } for(int i=1; i<=N*N; i++) { printf("%c",map[i]); } printf("\n"); return true; } int c; int tmp=inf; for(int i=dlx[head].r; i!=head; i=dlx[i].r) { if(dlx[i].s<tmp) { tmp=dlx[i].s; c=i; } } //cout<<c<<endl; remove(c); for(int i=dlx[c].d; i!=c; i=dlx[i].d) { q[k]=i; for(int j=dlx[i].r; j!=i; j=dlx[j].r) { remove(dlx[j].p); } if(dfs_dlx(k+1)) { return true; } for(int j=dlx[i].l; j!=i; j=dlx[j].l) { resume(dlx[j].p); } } resume(c); return false;}void connect(int r,int c)//插入r行,c列{ int tmp=++size; dlx[tmp].p=c; dlx[c].s++; x[tmp]=r; dlx[tmp].d=dlx[c].d; dlx[dlx[c].d].u=tmp; dlx[tmp].u=c; dlx[c].d=tmp; if(h[r]<0) { h[r]=tmp; dlx[tmp].l=tmp; dlx[tmp].r=tmp; } else { dlx[tmp].r=dlx[h[r]].r; dlx[dlx[h[r]].r].l=tmp; dlx[tmp].l=h[r]; dlx[h[r]].r=tmp; }}void place(int &r,int &c1,int &c2,int &c3,int &c4,int i,int j,int k)//放置函数,放在相应的位置{ r=(i*N+j)*N+k,c1=i*N+j+1,c2=N*N+i*N+k,c3=N*N*2+j*N+k,c4=N*N*3+((i/3)*3+(j/3))*N+k;}int main(){ // freopen("in.txt","r",stdin); int r,c1,c2,c3,c4; while(scanf("%s",map),map[0]!='e') { init(maxr,4*N*N); memset(v,0,sizeof(v)); for(int k=0,i=0; i<9; ++i) for(int j=0; j<9; ++j,++k) { if(map[k]>'0'&&map[k]<='9') { place(r,c1,c2,c3,c4,i,j,map[k]-'0'); connect(r,c1); connect(r,c2); connect(r,c3); connect(r,c4); v[c1]=1; v[c2]=1; v[c3]=1; v[c4]=1; } } for(int i=0;i<9;i++) for(int j=0;j<9;j++) for(int k=1;k<=9;k++) { place(r,c1,c2,c3,c4,i,j,k); if((v[c1]||v[c2]||v[c3]||v[c4])) { continue; } connect(r,c1); connect(r,c2); connect(r,c3); connect(r,c4); } dfs_dlx(0); } return 0;}
- poj 3074 Sudoku (精确覆盖,DLX,搜索)
- DLX(精确覆盖) POJ 3074 Sudoku
- POJ 3074 Sudoku DLX精确覆盖
- POJ 3074 Sudoku(DLX+精确覆盖)
- POJ 3074 Sudoku 转化精确覆盖问题DLX
- POJ 3076 Sudoku DLX精确覆盖
- POJ 3076 Sudoku 精确覆盖问题DLX
- DLX精确覆盖 poj2676 Sudoku
- HDU 4069 Squiggly Sudoku DLX 精确覆盖
- DLX精确覆盖 hdu4069 Squiggly Sudoku
- POJ 3074 Sudoku DLX
- DLX(精确覆盖) 16*16数独 POJ 3076 Sudoku
- LA 2659 && poj 3076 && zoj 3122 Sudoku(精确覆盖 + DLX)
- POJ 3074 DLX精确覆盖求解数独问题
- POJ 3740 DLX 精确覆盖模板题
- poj 3740 DLX(精确覆盖)
- POJ-3740-Easy Finding【DLX精确覆盖】
- HDU 3909 Sudoku(数独转DLX精确覆盖)
- UVa 11729 Commando War / 贪心
- OGRE之旅
- 面试题:非阻塞tcp socket调用close时缓冲区未发送数据的处理逻辑
- 好听的动情歌曲
- 一般图的最大匹配问题(真心觉得难)
- poj 3074 Sudoku (精确覆盖,DLX,搜索)
- 人生道路上的100个真相
- 两注意
- 黑马程序员——基础for循环的使用与理解
- 关于输出给定数组的k大小的子集
- 单例模式
- Memory leak detection in C++
- hdu——2546——饭卡(0-1背包)
- 区间调度问题