Time Limit: 10000MS | Memory Limit: 65536K | |
Total Submissions: 4918 | Accepted: 2332 |
Description
Write a Sudoku playing program that reads data sets from a text file.
Input
Output
Sample Input
--A----C-----O-I -J--A-B-P-CGF-H- --D--F-I-E----P- -G-EL-H----M-J-- ----E----C--G--- -I--K-GA-B---E-J D-GP--J-F----A-- -E---C-B--DP--O- E--F-M--D--L-K-A -C--------O-I-L- H-P-C--F-A--B--- ---G-OD---J----H K---J----H-A-P-L --B--P--E--K--A- -H--B--K--FI-C-- --F---C--D--H-N-
Sample Output
FPAHMJECNLBDKOGI OJMIANBDPKCGFLHE LNDKGFOIJEAHMBPC BGCELKHPOFIMAJDN MFHBELPOACKJGNID CILNKDGAHBMOPEFJ DOGPIHJMFNLECAKB JEKAFCNBGIDPLHOM EBOFPMIJDGHLNKCA NCJDHBAEKMOFIGLP HMPLCGKFIAENBDJO AKIGNODLBPJCEFMH KDEMJIFNCHGAOPBL GLBCDPMHEONKJIAF PHNOBALKMJFIDCEG IAFJOECGLDPBHMNK
Source
數獨題目
只不過變成了16x16的數獨……
正好也整理下數獨模板
題目中給的數據好像是pdf直接拷貝出bug的緣故
poj的是正常的LA和ZOJ好像都有問題
基本點不變
如果數獨是M*M的
那麼有M*M*M行
對應i行j列填數字k
M*M*4列
1~M*M i行j列有數字
M*M+1~M*M*2 i行有數字j
M*M*2+1~M*M*3 i列有數字j
M*M*3+1~M*M*4 i小九宮有數字j
特別測試
列的排佈會大範圍的影響速度
同樣的程序如果交換“i行j列有數字”列與“i小九宮有數字j”列
效率會低10倍……
使用place函數可以方便的算出第幾個小九宮
而且place變成類的成員函數速度更快(應該是被inline了,直接inline應該也可以……)
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int M=16;//數獨大小
const int MN=M*M*M+10;
const int MM=M*M*4+10;
const int MNN=MN*4+MM; //最大點數,數獨問題節點沒有那麼多
struct DLX
{
int n,m,si;//n行數m列數si目前有的節點數
//十字鏈表組成部分
int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
//第i個結點的U向上指針D下L左R右,所在位置Row行Col列
int H[MN],S[MM]; //記錄行的選擇情況和列的覆蓋情況
int ansd,ans[MN];
void init(int _n,int _m) //初始化空表
{
n=_n;
m=_m;
for(int i=0;i<=m;i++) //初始化第一橫行(表頭)
{
S[i]=0;
U[i]=D[i]=i; //目前縱向的鏈是空的
L[i]=i-1;
R[i]=i+1; //橫向的連起來
}
R[m]=0;L[0]=m;
si=m; //目前用了前0~m個結點
for(int i=1;i<=n;i++)
H[i]=-1;
}
void link(int r,int c) //插入點(r,c)
{
//cout<<"link r "<<r<<" c "<<c<<endl;
++S[Col[++si]=c]; //si++;Col[si]=c;S[c]++;
Row[si]=r;
D[si]=D[c];
U[D[c]]=si;
U[si]=c;
D[c]=si;
if(H[r]<0)
H[r]=L[si]=R[si]=si;
else
{
R[si]=R[H[r]];
L[R[H[r]]]=si;
L[si]=H[r];
R[H[r]]=si;
}
}
void remove(int c) //列表中刪掉c列
{
//cout<<"remove "<<c<<endl;
L[R[c]]=L[c];//表頭操作
R[L[c]]=R[c];
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!= i;j=R[j])
{
U[D[j]]=U[j];
D[U[j]]=D[j];
--S[Col[j]];
}
}
void resume(int c) //恢復c列
{
//cout<<"resume "<<c<<endl;
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]]=R[L[c]]=c;
}
bool dance(int d) //選取了d行
{
if(R[0]==0)//全部覆蓋了
{
//全覆蓋了之後的操作
ansd=d;
return 1;
}
int c=R[0];
for(int i=R[0];i!=0;i=R[i])
if(S[i]<S[c])
c=i;
remove(c);
for(int i=D[c];i!=c;i=D[i])
{
ans[d]=Row[i];
for(int j=R[i];j!= i;j=R[j])
remove(Col[j]);
if(dance(d+1))
return 1;
for(int j=L[i];j!=i;j=L[j])
resume(Col[j]);
}
resume(c);
return 0;
}
void place(int &r,int &c1,int &c2,int &c3,int &c4,int i,int j,int k)
{
r=(i*M+j)*M+k;
c1=M*M*0+i*M+j+1;
c2=M*M*1+i*M+k;
c3=M*M*3+j*M+k;
c4=M*M*2+((i/4)*4+(j/4))*M+k;//確定第幾個小九宮(16宮?),九宮4改3
}
}dlx;
char ss[M+5][M+5];
int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
int ca=0;
while(scanf("%s",ss[0])!=EOF)
{
for(int i=1;i<M;i++)
scanf("%s",ss[i]);
dlx.init(M*M*M,M*M*4);
int r,c1,c2,c3,c4;
for(int i = 0;i < M;i++)
for(int j = 0;j < M;j++)
for(int k = 1;k <= M;k++)
if(ss[i][j] == '-' || ss[i][j] == 'A'+k-1)
{
dlx.place(r,c1,c2,c3,c4,i,j,k);
dlx.link(r,c1);
dlx.link(r,c2);
dlx.link(r,c3);
dlx.link(r,c4);
}
dlx.dance(0);
int v,x,y;
for(int i=0;i<dlx.ansd;i++)
{
v=(dlx.ans[i]-1)%M;
x=(dlx.ans[i]-1)/M/M;
y=(dlx.ans[i]-1)/M%M;
ss[x][y]=v+'A';
}
if(ca++)
printf("\n");
for(int i=0;i<M;i++)
printf("%s\n",ss[i]);
}
return 0;
}