HDU - 3909
Time Limit: 20000MS | | Memory Limit: 65536KB | | 64bit IO Format: %I64d & %I64u |
Submit Status
Description
AmazingCaddy likes Sudoku very much. One day, he got some Sudoku problems and he wondered whether these problems are well designed. He needs your help now.
Sudoku is a logic-based, combinatorial number-placement puzzle. The objective is to fill a 9 × 9 grid with digits so that each column, each row, and each of the nine 3 × 3 regions contain all of the digits from 1 to 9.
-- Wikipedia
In this problem, the grid has three different sizes, with the formal (N^2) × (N^2), and N will be one in 2, 3 and 4. The rule is the same. The objective is to fill the (N^2) × (N^2) grid with characters so that each column, each row, and each of the N^2 regions (each size is N × N) contains all of the characters from 1 to 4(N = 2), 1 to 9(N = 3) or 1 to G (N = 4).
You task is that when you got a grid, you should tell the grid whether a puzzle or not. If it`s a puzzle, you should tell whether it is a minimal puzzle; else you should tell it has no solution or has multiple solutions.
A puzzle is a partially completed grid (the size is (N^2) × (N^2), N = 2, 3, 4), and has one and only one solution. If remove any character from a puzzle, it will lead to multiple solutions, then it is called a minimal puzzle.
Output
For each case:
If the grid is not a puzzle, and has no solution, print “No Solution”, or has multiple solutions print “Multiple Solutions”.
If the grid is a puzzle, but not a minimal, print “Not Minimal”, or print N lines represent the answer in the same format in the input, and ‘.’ should be replaced with the right characters. You can get more information from the sample output.
Sample Output
Not Minimal
Multiple Solutions
9BG86F253ED4A1C7
7ADC1GB4928F365E
F245EA73B61C98DG
3E6189CD7AG5F24B
E873461G59F2BDAC
492D3C5FA8EB7G61
15CF98AB6D7G43E2
B6AG2ED7C34189F5
8F3BG1E24CAD6579
C756F38A219EG4BD
D49A7B6CGF531E28
2G1E5D498B67CF3A
GCE4D5F617B82A93
6DF9C731EG2A5B84
51B7A298D436ECGF
A382B4GEF5C9D716
Source
2011 Multi-University Training Contest 7 - Host by ECNU
最全面的一道数独题了吧,最高可到16阶。。
这几天在研究DLX的时候,看到一篇文章,说了未经优化的dlx和经过优化的dlx差距巨大。而每次从1最少的列开始dance的话,可以优化大量的时间。一开始我对这句话是很怀疑的,感觉先后顺序应该和时间没什么关系吧,毕竟就是乘法满足交换律。直到我今天亲自写了一下,,,
一开始写了个未经优化的DLX,用上面的样例,第一个样例秒出,而第二个样子居然用了大概42s左右的时间才出结果。。第三个样例等了20多分钟,,怕把cpu烧坏就中止了。。。随后又写了个
每次从1最少的列开始dance的程序,,所用时间看图。。
3个样例一起运行居然只用了2s左右,,和未优化的相差几千倍啊,,太诡异了。。。
下面是AC代码,用时7s,,是有点长。。然后我又在网上找了一种听说很好的方法,那就是先构造已经有数字的格子行,然后在构造不定的格子的时候,将与已有格子行冲突的全弃掉。。。。。我也满怀期待的写了一下,,结果运行时间居然和原先差不多!几乎是一模一样。。。。统计了下对于第三个样例最后构造成01矩阵的行数,原先是大概2705行,经过“优化”后,行数减到了900多行。。可以说大量减少。。。可是时间为啥一样啊。。。。。。
#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<string.h>
#include<cstring>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f
#define mem(x,y) memset(x,y,sizeof(x))
typedef long long LL;
int k,n,colnum[4*16*16+10],cnt,totnum;
char sudoku[17][17],sudoku1[17][17];
stack<int> mystack,mystack1;
struct {
int u,d,l,r,x,y;
} node[200000];
void buildnode(int x,int y,int v) {
colnum[y]++;
cnt++;
node[cnt]= {cnt,cnt,cnt,cnt,x,y};
//与上下节点连接
node[node[y].u].d=cnt;
node[cnt].u=node[y].u;
node[cnt].d=y;
node[y].u=cnt;
//与左右节点连接
if(node[cnt-1].x==x) {
node[node[cnt-1].r].l=cnt;
node[cnt].r=node[cnt-1].r;
node[cnt-1].r=cnt;
node[cnt].l=cnt-1;
}
}
void buildhang(int i,int j,int x) {
int xx=((i-1)*n+j-1)*n+x;
buildnode(xx,n*(k*((i-1)/k)+(j-1)/k)+x,x);//宫
buildnode(xx,n*n+(i-1)*n+x,x);//行
buildnode(xx,2*n*n+(j-1)*n+x,x);//列
buildnode(xx,3*n*n+(i-1)*n+j,x);//格子
}
int getnum(char c) {
if(c>='A') return 10+c-'A';
else return c-'0';
}
void build() {
//将node【0】作为整个dancelink的头结点
node[0]= {0,0,0,0,0,0}; //初始化头结点
int prenode=0;
for(int i=1; i<=n*n*4; i++) { //初始化表头节点
node[i]= {i,i,i,i,0,i};
node[i].r=node[prenode].r;
node[node[prenode].r].l=i;
node[prenode].r=i;
node[i].l=prenode;
prenode=i;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
if(sudoku[i][j]!='.') buildhang(i,j,getnum(sudoku[i][j]));
else for(int w=1; w<=n; w++) buildhang(i,j,w);
}
}
void Remove(int x) {
node[node[x].l].r=node[x].r;
node[node[x].r].l=node[x].l;
int nownode=node[x].d,p;
while(nownode!=x) {
p=node[nownode].r;
while(p!=nownode) {
colnum[node[p].y]--;
node[node[p].u].d=node[p].d;
node[node[p].d].u=node[p].u;
p=node[p].r;
}
nownode=node[nownode].d;
}
}
void Resume(int x) {
node[node[x].l].r=x;
node[node[x].r].l=x;
int nownode=node[x].d,p;
while(nownode!=x) {
p=node[nownode].r;
while(p!=nownode) {
colnum[node[p].y]++;
node[node[p].u].d=p;
node[node[p].d].u=p;
p=node[p].r;
}
nownode=node[nownode].d;
}
}
int minnode() {//最小头结点
int minn=INF,y=0,nownode=node[0].r;
while(nownode!=0) {
if(colnum[node[nownode].y]<minn) {
minn=colnum[node[nownode].y];
y=node[nownode].y;
}
nownode=node[nownode].r;
}
return y;
}
int dance() {
int nownode=minnode(),p1,p2;
if(nownode==0) {
totnum++;
if(totnum==2) return 1;
mystack1=mystack;
return 0;
}
p1=node[nownode].d;
if(p1==nownode) return 0;
Remove(node[nownode].y);
while(p1!=nownode) {
mystack.push(node[p1].x);
p2=node[p1].r;
while(p2!=p1) {
Remove(node[p2].y);
p2=node[p2].r;
}
if(dance()) return 1;
p2=node[p1].l;
while(p2!=p1) {
Resume(node[p2].y);
p2=node[p2].l;
}
mystack.pop();
p1=node[p1].d;
}
Resume(node[nownode].y);
return 0;
}
int _find1(int x) {
return (x-1)/n+1;
}
char Getchar(int x) {
int t=(x-1)%n+1;
if(t<=9) return '0'+t;
else return 'A'+t-10;
}
void print() {//打印路径
for(int i =1; i<=n; i++) {
for(int j=1; j<=n; j++)cout<<sudoku1[i][j];
cout<<endl;
}
}
void DLX() {
while(!mystack.empty()) mystack.pop();
totnum=0;
mem(colnum,0);
cnt=n*n*4;
build();
dance();
}
bool is_min() {//是否为<span style="font-family: Arial, Helvetica, sans-serif;">Minimal
</span>char c;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
if(sudoku[i][j]!='.') {
c=sudoku[i][j];
sudoku[i][j]='.';
DLX();
sudoku[i][j]=c;
if(totnum!=2) return false;
}
}
return 1;
}
int main() {
// freopen("input.txt","r",stdin);
while(cin>>k) {
n=k*k;
char c;
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) cin>>sudoku[i][j];
DLX();
if(totnum==2) cout<<"Multiple Solutions"<<endl;
else if(totnum==0) {
cout<<"No Solution"<<endl;
} else {
while(!mystack1.empty()) {
int x=mystack1.top();
mystack1.pop();
int gps=_find1(x);
sudoku1[(gps-1)/n+1][(gps-1)%n+1]=Getchar(x);
}
if(is_min())print();
else cout<<"Not Minimal"<<endl;
}
}
return 0;
}
|