题意:N行M列的0 1矩阵(1 <= N,M <= 1000),求选出其中的一些行,使得选出的这些行每列有且仅有一个1,输出选出行的行号,无解输出"NO"。
题目链接:http://acm.hust.edu.cn/problem/show/1017
——>>DLX 练手。。
#include <cstdio>
#include <cstring>const int MAXN = 1000 + 10;
const int MAXNODE = MAXN * MAXN;struct DLX
{int sz;int H[MAXN], S[MAXN];int row[MAXNODE], col[MAXNODE];int U[MAXNODE], D[MAXNODE], L[MAXNODE], R[MAXNODE];int ret[MAXN], cnt;void Init(int n){for (int i = 0; i <= n; ++i){U[i] = D[i] = i;L[i] = i - 1;R[i] = i + 1;}L[0] = n;R[n] = 0;sz = n + 1;cnt = 0;memset(S, 0, sizeof(S));memset(H, -1, sizeof(H));}void Link(const int& r, const int& c){row[sz] = r;col[sz] = c;D[sz] = D[c];U[D[c]] = sz;D[c] = sz;U[sz] = c;if (H[r] == -1){H[r] = L[sz] = R[sz] = sz;}else{R[sz] = R[H[r]];L[R[H[r]]] = sz;R[H[r]] = sz;L[sz] = H[r];}S[c]++;sz++;}void Remove(const int& c){L[R[c]] = L[c];R[L[c]] = R[c];for (int i = D[c]; i != c; i = D[i]){for (int j = R[i]; j != i; j = R[j]){U[D[j]] = U[j];D[U[j]] = D[j];S[col[j]]--;}}}void Restore(const int& c){for (int i = U[c]; i != c; i = U[i]){for (int j = L[i]; j != i; j = L[j]){S[col[j]]++;U[D[j]] = j;D[U[j]] = j;}}L[R[c]] = c;R[L[c]] = c;}bool Dfs(int cur){if (R[0] == 0){cnt = cur;return true;}int c = R[0];for (int i = R[0]; i != 0; i = R[i]){if (S[i] < S[c]){c = i;}}Remove(c);for (int i = D[c]; i != c; i = D[i]){ret[cur] = row[i];for (int j = R[i]; j != i; j = R[j]){Remove(col[j]);}if (Dfs(cur + 1)) return true;for (int j = L[i]; j != i; j = L[j]){Restore(col[j]);}}Restore(c);return false;}void Solve(){if (!Dfs(0)){puts("NO");}else{printf("%d", cnt);for (int i = 0; i < cnt; ++i){printf(" %d", ret[i]);}puts("");}}
} dlx;int N, M;void Read()
{int cnt, c;dlx.Init(M);for (int i = 1; i <= N; ++i){scanf("%d", &cnt);while (cnt--){scanf("%d", &c);dlx.Link(i, c);}}
}int main()
{while (scanf("%d%d", &N, &M) != EOF){Read();dlx.Solve();}return 0;
}