精确覆盖(dancing link)的板子题。
参考了下面的博客:
这个博客虽然不是用c++写的代码,但讲的十分详细,有助于理解。http://www.cnblogs.com/grenet/p/3145800.html
又短又漂亮的c++代码,值得一膜:http://blog.csdn.net/xianxingwuguan1/article/details/18994601
下面是我的代码(实际上长得和上面那个博客里的一膜一样)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define ll long long
#define db double
#define mkp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define X first
#define Y second
const int N=20,M=305,NM=7000;
int n,m;
struct DLX{
int L[NM],R[NM],U[NM],D[NM]/*,ro[NM]*/,co[NM],H[N],S[M]/*,cnt*/,sz/*,ans[N]*/;//H为行首,S为每列元素个数
void reset(){
int i;rep(i,0,m)
S[i]=0,L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;
L[0]=m,R[m]=0,sz=m+1;
memset(H,-1,sizeof H);
}
void ins(int x,int y){
++S[co[sz]=y]/*,ro[sz]=x*/;//确定所在行、列
U[D[sz]=D[y]]=sz;
U[D[y]=sz]=y;//将sz插入y和D[y]中
if(H[x]<0)H[x]=L[sz]=R[sz]=sz;
else{
L[R[sz]=R[H[x]]]=sz;
R[L[sz]=H[x]]=sz;
}//将sz插入H[x]和R[H[x]]中
++sz;
}
void del(int c){
R[L[R[c]]=L[c]]=R[c];
int i,j;
for(i=D[c];i!=c;i=D[i])
for(j=R[i];j!=i;j=R[j])
D[U[D[j]]=U[j]]=D[j],--S[co[j]];
}
void add(int c){
R[L[c]]=L[R[c]]=c;
int i,j;
for(i=U[c];i!=c;i=U[i])
for(j=L[i];j!=i;j=L[j])
++S[co[U[D[j]]=D[U[j]]=j]];
}
bool DFS(/*int k*/){
if(!R[0]){
/*cnt=k;*/return 1;
}
int c,i,j;
for(i=c=R[0];i;i=R[i])if(S[c]>S[i])c=i;//找出元素最多的一列
del(c);
for(i=D[c];i!=c;i=D[i]){
for(j=R[i];j!=i;j=R[j])del(co[j]);
// ans[k]=ro[i];
if(DFS(/*k+1*/))return 1;
for(j=L[i];j!=i;j=L[j])add(co[j]);
}
add(c);
return 0;
}
}dlx;
int main(){
int i,j,x;
while(~scanf("%d%d",&n,&m)){
dlx.reset();
rep(i,1,n)rep(j,1,m){
scanf("%d",&x);
if(x)dlx.ins(i,j);
}
puts(dlx.DFS(/*0*/)?"Yes, I found it":"It is impossible");
}
return 0;
}