经典N皇后问题,本来是做POJ3239的,结果写完了才发现n最大300..DLX一样会超时,而且那题居然是构造做的...spoj上n最多只有50,而且初始会给出若干个已有皇后的位置。建表时可以建成n*n行*(6*n-2)列的01矩阵,其中行表示每个格子的位置,列的话,前n列n是第i行,下n列是第j列,在下面2*n-1列是左斜线,最后2*n-1列是又斜线。每行恰好有4个1。然后就是去搜了..这题有一点要注意,就是结束状态时,行列一定是完全覆盖的,但是左斜线右斜线不一定会完全覆盖。所以每一次搜索时,找第一个位置时要有一点变化,具体实现看代码吧,在这里还坑了挺长时间的,不过A掉这题后,感觉已经完全明白了DLX是怎么回事了...
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int tt=60;
const int maxr=tt*tt;
const int maxc=6*tt;
const int maxn=maxr*maxc;
int col[maxn],row[maxn],R[maxn],L[maxn],U[maxn],D[maxn];
int ct[10];
int a[55];
int head[tt][tt];
int S[maxr];
int size,mRow;
int n,m,k;
struct ANS
{
int x,y;
}ans[maxr];
int anss[330];
int st[maxr];
struct DLX
{
void resume(int c)
{
L[R[c]]=c;
R[L[c]]=c;
for (int i=U[c]; i!=c; i=U[i])
for (int j=L[i]; j!=i; j=L[j])
{
U[D[j]]=j;
D[U[j]]=j;
++S[col[j]];
}
}
void remove(int c)
{
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 init(int m)
{
for (int i=1; i<=m; i++)
{
L[i]=i-1;
R[i]=i+1;
U[i]=D[i]=i;
S[i]=0;
col[i]=i;
row[i]=0;
}
L[0]=m;
R[0]=1;
R[m]=0;
U[0]=D[0]=0;
size=m;
mRow=0;
}
int makehead(int c)
{
size++;
S[c]++;
col[size]=c;
row[size]=mRow;
L[size]=R[size]=size;
U[size]=c;
D[size]=D[c];
U[D[size]]=D[U[size]]=size;
return size;
}
void addcol(int id,int c)
{
size++;
S[c]++;
col[size]=c;
row[size]=mRow;
L[size]=id;
R[size]=R[id];
L[R[size]]=R[L[size]]=size;
U[size]=c;
D[size]=D[c];
U[D[size]]=D[U[size]]=size;
}
void addrow(int i,int j)
{
int id;
mRow++;
ans[mRow].x=i;
ans[mRow].y=j;
id=makehead(i+ct[0]);
head[i][j]=id;
addcol(id,j+ct[1]);
addcol(id,i+j+ct[2]);
addcol(id,i-j+n-1+ct[3]);
}
bool dfs(int k)
{
if (k==n)
{
for (int i=0; i<k; i++)
if (a[ans[st[i]].x]==0)anss[ans[st[i]].x]=ans[st[i]].y;
return true;
}
int c;
int minn=(1<<28);
for (int i=R[0]; i<=n; i=R[i])
{
if (!S[i]) return false;
if (S[i]<minn)
{
minn=S[i];
c=i;
}
}
remove(c);
for (int i=D[c]; i!=c; i=D[i])
{
st[k]=row[i];
for (int j=R[i]; j!=i; j=R[j]) remove(col[j]);
if (dfs(k+1)) return true;
for (int j=L[i]; j!=i; j=L[j]) resume(col[j]);
}
resume(c);
return false;
}
}dlx;
int main()
{
while(~scanf("%d",&n))
{
for (int i=0; i<n; i++)
scanf("%d",&a[i]);
ct[0]=1;
ct[1]=n+1;
ct[2]=(n<<1)+1;
ct[3]=(n<<2);
dlx.init(6*n-2);
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
{
dlx.addrow(i,j);
}
int k=0;
for (int i=0; i<n; i++)
{
if (a[i])
{
k++;
int x=head[i][a[i]-1];
anss[i]=a[i]-1;
dlx.remove(col[x]);
for (int i=R[x]; i!=x; i=R[i]) dlx.remove(col[i]);
}
}
if (dlx.dfs(k))
{
cout<<anss[0]+1;
for (int i=1; i<n; i++)
cout<<" "<<anss[i]+1;
cout<<endl;
}
}
return 0;
}