题意:经典的精确覆盖问题。
思路:精确覆盖问题是NPC的,用DLX能够比较有效的搜索。写完两个数独再写这个就不难了(实际上这个是原始问题,数独只是DLX的应用)。
#include <cstdio>
#include <cstring>
#define N 16
#define M 300
struct node{
int l,r,u,d,x,y;
}p[N*M+M+5];
int s[N+5][M+5];
int n,m,top,cnt[M];
void init(){
int i;
memset(cnt, 0, sizeof(cnt));
for(i = 0;i<=m;i++){
p[i].l = i-1;
p[i].r = i+1;
p[i].u = p[i].d = i;
}
p[0].l = m;
p[m].r = 0;
top = m;
}
void add(int l,int i,int j){
p[++top].x = i;
p[top].y = j;
p[top].l = l;
p[p[top].l].r = top;
p[top].u = p[j].u;
p[p[top].u].d = top;
p[j].u = top;
p[top].d = j;
cnt[j]++;
}
void del(int c){
int i,j;
p[p[c].l].r = p[c].r;
p[p[c].r].l = p[c].l;
for(i = p[c].d;i!=c;i=p[i].d){
for(j = p[i].r;j!=i;j=p[j].r){
p[p[j].u].d = p[j].d;
p[p[j].d].u = p[j].u;
cnt[p[j].y]--;
}
}
}
void re(int c){
int i,j;
p[p[c].l].r = c;
p[p[c].r].l = c;
for(i = p[c].d;i!=c;i=p[i].d)
for(j = p[i].r;j!=i;j=p[j].r){
p[p[j].u].d = j;
p[p[j].d].u = j;
cnt[p[j].y]++;
}
}
int dfs(){
int min=0x3fffffff,c=0,i,j;
if(!p[0].r)
return 1;
for(i = p[0].r;i;i=p[i].r)
if(cnt[i] < min){
c = i;
min = cnt[i];
}
del(c);
for(i = p[c].d;i!=c;i=p[i].d){
for(j = p[i].r;j!=i;j=p[j].r)
del(p[j].y);
if(dfs())
return 1;
for(j = p[i].l;j!=i;j=p[j].l)
re(p[j].y);
}
re(c);
return 0;
}
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
int i,j,first;
init();
for(i = 1;i<=n;i++){
s[i][0] = 0;//保存一行中1的个数
for(j = 1;j<=m;j++){
scanf("%d",&s[i][j]);
if(s[i][j])
s[i][0]++;
}
}
for(i = 1;i<=n;i++)
for(j = first = 1;j<=m;j++)
if(s[i][j]){
if(first){
first = 0;
add(top+s[i][0], i, j);
}else
add(top, i, j);
}
if(dfs())
printf("Yes, I found it\n");
else
printf("It is impossible\n");
}
return 0;
}