有没有什么别的UVA的镜像网站,vjudge也太慢了,交一次要等一分钟两分钟,我这个急性子真的受不了!还是说所有的镜像网站都一样。
题目:sudoku(数独)
我把代码交在spoj一样的题目上过了,UVA一直超时,求大佬调试。(蒟蒻第一次挑战黑题,代码可能和题解相似,但我理解了,并非复制粘贴抄袭)
#include<bits/stdc++.h>
using namespace std;
const int N=1<<16,M=19;
char s[M][M];
int num[N],cnt[N],fe[M][M];
//cnt 一个数换成二进制,里面有多少个1
//num 这个数是2的几次方
inline void update(int x,int y,int z) //让所有相关的位置不能为z
{
for(int i=1; i<=16; i++)
{
fe[x][i]&=~(1<<z);
fe[i][y]&=~(1<<z);
}
int stx=(x-1)/4*4+1,sty=(y-1)/4*4+1;//16宫格左上角
for(int i=stx; i<stx+4; i++)
{
for(int j=sty; j<sty+4; j++)
fe[i][j]&=~(1<<z);
}
}
bool dfs(int left)
{
// cout<<left<<endl;
if(!left)
{
for(int i=1; i<=16; i++) printf("%s\n",s[i]+1);
return 1;
}
int fe_save[M][M];
memcpy(fe_save,fe,sizeof(fe_save));
int mn=17,nx,ny;
for(int i=1; i<=16; i++) //只有一个能填的填了
{
for(int j=1; j<=16; j++)
{
if(s[i][j]!='-') continue;
if(!fe[i][j]) return 0;
if(cnt[fe[i][j]]==1)
{
s[i][j]=num[fe[i][j]]+'A';
update(i,j,num[fe[i][j]]);
if(dfs(left-1)) return 1;
s[i][j]='-';
memcpy(fe,fe_save,sizeof(fe_save));
return 0;
}
if(cnt[fe[i][j]]<mn)
{
mn=cnt[fe[i][j]];
nx=i;
ny=j;
}
}
}
for(int i=1; i<=16; i++) //某个字母不能填在某一行的任何位置则回溯;只能填在一个位置则向下搜索。
{
int vis=0,now_left=0;
for(int j=1; j<=16; j++) //第i行有几个空,哪些数字已经被填了
{
if(s[i][j]=='-') now_left++;
else vis|=1<<(s[i][j]-'A');
}
if(!now_left) continue;
for(int j=0; j<16; j++)
{
if(vis>>j&1) continue;
int cntt=0,last;
for(int k=1; k<=16; k++)
{
if(s[i][k]!='-') continue;
if(!(fe[i][k]>>j&1)) continue;
cntt++;
last=k;
if(cntt>=2) break;
}
if(!cntt) return 0;
if(cntt==1)
{
s[i][last]=j+'A';
update(i,last,j);
if(dfs(left-1))return 1;
s[i][last]='-';
memcpy(fe,fe_save,sizeof(fe_save));
return 0;
}
}
}
for(int i=1; i<=16; i++) //某个字母不能填在某一列的任何位置则回溯;只能填在一个位置则向下搜索。
{
int vis=0,now_left=0;
for(int j=1; j<=16; j++) //第i行有几个空,哪些数字已经被填了
{
if(s[j][i]=='-') now_left++;
else vis|=1<<(s[j][i]-'A');
}
if(!now_left) continue;
for(int j=0; j<16; j++)
{
if(vis>>j&1) continue;
int cntt=0,last;
for(int k=1; k<=16; k++)
{
if(s[k][i]!='-') continue;
if(!(fe[k][i]>>j&1)) continue;
cntt++;
last=k;
if(cntt>=2) break;
}
if(!cntt) return 0;
if(cntt==1)
{
s[last][i]=j+'A';
update(last,i,j);
if(dfs(left-1))return 1;
s[last][i]='-';
memcpy(fe,fe_save,sizeof(fe_save));
return 0;
}
}
}
for (int x=1; x<=13; x+=4) //16宫格,枚举起点 (x,y)
{
for (int y=1; y<=13; y+=4)
{
int vis=0,now_left=0;
for (int i=x; i<x+4; i++) //遍历所有点
{
for (int j=y; j<y+4; j++)
{
if (s[i][j]=='-') now_left++;
else vis|=1<<(s[i][j]-'A'); //已填
}
}
if (!now_left) continue; //填满
for (int k=0; k<16; k++) //枚举字母
{
if (vis>>k&1) continue;
int cntt=0,lastx,lasty;
for (int i=x; i<x+4; i++)
{
for (int j=y; j<y+4; j++)
{
if (s[i][j]!='-') continue;
if (!(fe[i][j]>>k&1)) continue;
cntt++;
lastx=i;
lasty=j;
}
}
if (!cntt) return 0;
if (cntt==1)
{
s[lastx][lasty]=k+'A';
update(lastx,lasty,k);
if (dfs(left-1)) return 1;
s[lastx][lasty]='-';
memcpy(fe,fe_save,sizeof(fe_save));
return 0;
}
}
}
}
for (int i=fe[nx][ny]; i; i-=i&-i) //对可填字母最少的点进行枚举搜索
{
int z=num[i&-i];
s[nx][ny]=z+'A';
update(nx,ny,z);
if (dfs(left-1)) return 1;
s[nx][ny]='-';
memcpy(fe,fe_save,sizeof(fe));
}
return 0;
}
int T=0;
int main()
{
for(int i=0; i<16; i++) num[1<<i]=i;
for(int i=0; i<N; i++)
{
for(int j=i; j; j-=j&-j)
cnt[i]++;
}
//cin>>T;
while(scanf("%s",s[1]+1))
{
if(T) puts("");
T=1;
for(int i=2; i<=16; i++)
scanf("%s",s[i]+1);
for(int i=1; i<=16; i++)
{
for(int j=1; j<=16; j++)
fe[i][j]=N-1;
}
int left=0;
for(int i=1; i<=16; i++)
{
for(int j=1; j<=16; j++)
{
if(s[i][j]=='-') left++;
else update(i,j,s[i][j]-'A');
}
}
dfs(left);
}
}