题意:
给你一个n*m(n<=16,m<=300)的矩阵。矩阵的每个元素只能是0或1.现在问你能不能从里面选一些列出来使的没一列有且仅有一个1.
#include<cstdio>
#define INF 0x7FFFFFFF
#define MAXN 90010
int n, m, size;
int L[MAXN], R[MAXN], U[MAXN], D[MAXN], H[MAXN]; //H[i] 是i行的头指针,指向改行的第一个结点
int C[MAXN],row[MAXN] ,S[MAXN]; //C[i] 是i结点所在的列号 ,row[i]是i结点所在的行,s[i]是i列的结点数量 ;
void Init() {
int i;
for (i = 1; i <= n; i++)
H[i] = -1;
for (i = 0; i <= m; i++) {
S[i] = 0;
L[i + 1] = i;
R[i] = i + 1;
U[i] = D[i] = i;
}
R[m] = 0;
size = m + 1;
}
void Link(int r, int c) { //构造十字链表
U[size] = c;
D[size] = D[c];
U[D[c]] = size;
D[c] = size;
if (H[r] < 0)
H[r] = L[size] = R[size] = size;
else {
L[size] = H[r];
R[size] = R[H[r]];
L[R[H[r]]] = size;
R[H[r]] = size;
}
S[c]++;
row[size]=r;
C[size++] = c;
}
void Remove(int c) { //删除c列及相应的行
int i, j;
R[L[c]] = R[c];
L[R[c]] = L[c];
for (i = D[c]; i != c; i = D[i]) {
for (j = R[i]; j != i; j = R[j]) {
U[D[j]] = U[j];
D[U[j]] = D[j];
S[C[j]]--;
}
}
}
void Resume(int c) { //恢复c列
int i, j;
R[L[c]] = c;
L[R[c]] = c;
for (i = D[c]; i != c; i = D[i]) {
for (j = R[i]; j != i; j = R[j]) {
U[D[j]] = j;
D[U[j]] = j;
S[C[j]]++;
}
}
}
bool Dance(int now) { //舞蹈链
if (R[0] == 0) //输出答案
return true;
int i, j, temp, c;
for (temp=INF,i = R[0]; i; i = R[i]) {
if(S[i]<temp)
{
temp=S[i];
c=i;
}
}
Remove(c);
for(i=D[c];i!=c;i=D[i])
{ // ans[now]=row[i] ; 如果要输入答案是哪些行 ;
for(j=R[i];j!=i;j=R[j])
Remove(C[j]);
if(Dance(now+1))
return true;
for(j=L[i];j!=i;j=L[j])
Resume(C[j]);
}
Resume(c);
return false;
}
int main() {
int i, j, k;
while (~scanf("%d%d", &n, &m)) {
Init();
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
scanf("%d", &k);
if (k)
Link(i, j);
}
}
if (Dance(0))
puts("Yes, I found it");
else
puts("It is impossible");
}
return 0;
}