题意是给了n*m的01矩阵,选择最少的行,使得每一列都恰好包含一个1,然后输出这些行
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
const int maxm = 110;
const int maxnode = 110 * 110;
int L[maxnode], R[maxnode], U[maxnode], D[maxnode];
int C[maxnode],H[maxn],cnt[maxm],vis[maxn],ans[maxn],Row[maxnode];
int n,m,id,len;
void init(){
for(int i=0;i<=m;i++){
cnt[i] = 0; U[i] = D[i] = i;
L[i + 1] = i; R[i] = i + 1;
}
R[m] = 0; id = m + 1;
memset(H, -1, sizeof(H));
}
void Link(int r, int c){
cnt[c]++; C[id] = c; Row[id] = r;
U[id] = U[c]; D[ U[c] ] = id;
D[id] = c; U[c] = id; Row[id] = r;
if(H[r] == -1) H[r] = L[id] = R[id] = id;
else{
L[id] = L[ H[r] ]; R[ L[ H[r] ] ] = id;
R[id] = H[r]; L[ H[ r ] ] = id;
}
id++;
}
void Remove(int Size){
L[ R[Size] ] = L[Size];
R[ L[Size] ] = R[Size];
for(int i=D[Size];i!=Size;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
U[ D[j] ] = U[j]; D[ U[j] ] = D[j];
cnt[ C[j] ]--;
}
}
}
void Resume(int Size){
for(int i=D[Size];i!=Size;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
U[ D[j] ] = j; D[ U[j] ] = j;
cnt[ C[j] ]++;
}
}
L[ R[Size] ] = Size;R[ L[Size] ] = Size;
}
bool DLX(int k){
int pos,mm = maxn;
if(R[0] == 0){
len = k;
return true;
}
for(int i=R[0];i;i=R[i]){
if(mm > cnt[i]){
mm = cnt[i];
pos = i;
}
}
Remove(pos);
for(int i=D[pos];i!=pos;i=D[i]){
ans[k] = Row[i];
for(int j=R[i];j!=i;j=R[j]) Remove(C[j]);
if(DLX(k + 1)) return true;
for(int j=L[i];j!=i;j=L[j]) Resume(C[j]);
}
Resume(pos);
return false;
}
int main(){
int u,v,a;
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=n;i++){
int xx;
scanf("%d",&xx);
for(int j=1;j<=xx;j++){
int yy;
scanf("%d",&yy);
Link(i, yy);
}
}
bool ans1 = DLX(0);
if(ans1 == false) printf("No\n");
else{
printf("%d",len);
for(int i=0;i<len;i++){
printf(" %d",ans[i]);
}
puts("");
}
}
return 0;
}