位运算裸搜版(500ms):
#include <cstdio>
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
const int N=32;
const int L=10;
LL w[L],goal[L],x[20][L];
int m,n,a[20][320];
inline bool cont(LL *x,LL *y)
{
for (int i=0; i<m; i++)
{
if (x[i/N]&(1<<(i%N)) && y[i/N]&(1<<(i%N))) return true;
}
return false;
}
bool dfs(int i)
{
bool flag=true;
for (int k=0; k<L && flag; k++) if (goal[k]!=w[k]) flag=false;
if (flag) return true;
if (i>n) return false;
if (cont(w,x[i])) return dfs(i+1);
LL tmp[L];
for (int k=0; k<L; k++) tmp[k]=w[k],w[k]+=x[i][k];
if (dfs(i+1)) return true;
for (int k=0; k<L; k++) w[k]=tmp[k];
if (dfs(i+1)) return true;
return false;
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
memset(x,0,sizeof(x));
for (int i=1; i<=n; i++)
{
for (int j=0; j<m; j++)
{
scanf("%d",&a[i][j]);
if (a[i][j]) x[i][j/N]|=1<<(j%N);
}
}
memset(goal,0,sizeof(goal));
for (int j=0; j<m; j++) goal[j/N]|=1<<(j%N);
memset(w,0,sizeof(w));
if (dfs(1)) printf("Yes, I found it\n");
else printf("It is impossible\n");
}
return 0;
}
Dance Links版(63ms):
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int NN=6000;
const int INF=10000000;
int n,m,cnt,head,L[NN],R[NN],U[NN],D[NN],S[NN],C[NN],H[NN];
inline void add_link(int i,int j)
{
C[++cnt]=j;
S[j]++;
D[cnt]=j;
U[cnt]=U[j];
if (H[i]) R[cnt]=H[i],L[cnt]=L[H[i]];
else R[cnt]=L[cnt]=cnt;
H[i]=cnt;
U[D[cnt]]=cnt;
D[U[cnt]]=cnt;
R[L[cnt]]=cnt;
L[R[cnt]]=cnt;
}
void remove(int c)//删除第c列上的元素所在的行
{
R[L[c]]=R[c];
L[R[c]]=L[c];
//删除c,c是列指针,删除了c就代表删除了整列,因为递归后不可能访问到c了
for (int i=D[c]; i!=c; i=D[i]) //c所在列上的元素i
for (int j=R[i]; j!=i; j=R[j]) //i和j一行的,删掉j
{
U[D[j]]=U[j];
D[U[j]]=D[j];
S[C[j]]--;//j所在列的元素(‘1’的个数)-1;
}
}
void resume(int c)//对应的恢复操作
{
for (int i=U[c]; i!=c; i=U[i])
for (int j=L[i]; j!=i; j=L[j])
{
D[U[j]]=j;
U[D[j]]=j;
S[C[j]]++;
}
L[R[c]]=R[L[c]]=c;
}
bool dance()
{
if (R[head]==head)//列指针删完了,任务完成
{
puts("Yes, I found it");
return true;
}
int s(INF),c;
for (int i=R[head]; i!=head; i=R[i]) if (S[i]<s) s=S[i],c=i;
//找元素最少的列c,一种优化
remove(c);//删除列c
for (int i=D[c]; i!=c; i=D[i])
{
for (int j=R[i]; j!=i; j=R[j]) remove(C[j]);//删除所有可能的冲突元素
if (dance()) return true;
for (int j=L[i]; j!=i; j=L[j]) resume(C[j]);
}
resume(c);
return false;
}
int main()
{
int c;
head=0;
while (~scanf("%d%d",&n,&m))
{
cnt=m;
for (int i=0; i<=m; i++)
{
C[i]=U[i]=D[i]=i;
//这里C[i]没有赋值时也过了,因为不会有对列指针取列标号的操作
L[i+1]=i;
R[i]=i+1;
S[i]=0;
}
L[0]=m; R[m]=0; //初始化十字链表
for (int i=1; i<=n; i++)
{
H[i]=0;
for (int j=1; j<=m; j++)
{
c=getchar();
while (!isdigit(c)) c=getchar();
if (c=='1') add_link(i,j);
}
}
if (!dance()) puts("It is impossible");
}
return 0;
}