- 精确覆盖问题
- 使用 dancing links
- 本质思想是十字链表
#include<iostream>
#include<cstdio>
#define MAXN 510
#define MAXM 510
#define MAX (MAXN*MAXM)
using namespace std;
int n,m;
struct DLX{
int n,m,sz;
int U[MAX],D[MAX],R[MAX],L[MAX],row[MAX],col[MAX];
int H[MAXN],S[MAXM];
int res[MAXN];
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;
sz=m;
for(int i=1;i<=n;i++)H[i]=-1;
}
void link(int r,int c){
++S[col[++sz]=c];
row[sz]=r;
D[sz]=D[c];
U[D[c]]=sz;
U[sz]=c;
D[c]=sz;
if(H[r]<0)H[r]=L[sz]=R[sz]=sz;
else{
R[sz]=R[H[r]];
L[R[sz]]=sz;
L[sz]=H[r];
R[L[sz]]=sz;
}
}
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 resume(int c){
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){
if(R[0]==0){
for(int i=0;i<d;i++)
printf("%d ",res[i]);
return true;
}
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]){
res[d]=row[i];
for(int j=R[i];j!=i;j=R[j])remove(col[j]);
if(dance(d+1))return true;
for(int j=L[i];j!=i;j=L[j])resume(col[j]);
}
resume(c);
return false;
}
};
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
DLX d;
scanf("%d%d",&n,&m);
d.init(n,m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
int k;
scanf("%d",&k);
if(k)d.link(i+1,j+1);
}
if(!d.dance(0))
printf("No Solution!\n");
return 0;
}