二分图匹配
题意:给定一个r*c的棋盘,其中每列有2个白色格子,其余为黑色。要求选出c个白色格子,且每列一个,且每行至少一个。问能否实现,给出方案。
分析:如果r>c则必定无法满足,因为即使每列一个,均位于不同行,还是会有某些行没有被选中的格子。对于其余情况,先进行简单的二分图匹配(每行作为1点构成第一点集,每列作为1点构成第二点集,每个白色格子作为连接其行列点的边),如果每行都能匹配上则首先可以保证每行都有选中的格子,当然此时可能有一些列还有没有被选中的格子,只要在该列里随便选1个白的就行了,不会影响结果。
View Code
#include#include #include #include using namespace std; #define maxn 1005 int uN, vN; bool g[maxn][maxn]; int xM[maxn], yM[maxn]; bool chk[maxn]; bool SearchPath(int u) { int v; for (v = 0; v < vN; v++) if (g[u][v] && !chk[v]) { chk[v] = true; if (yM[v] == -1 || SearchPath(yM[v])) { yM[v] = u; xM[u] = v; return true; } } return false; } int MaxMatch() { int u, ret = 0; memset(xM, -1, sizeof(xM)); memset(yM, -1, sizeof(yM)); for (u = 0; u < uN; u++) { if (xM[u] == -1) memset(chk, false, sizeof(chk)); if (SearchPath(u)) ret++; } return ret; } void input() { scanf("%d%d", &uN, &vN); memset(g, 0, sizeof(g)); for (int i = 0; i < vN; i++) { int a, b; scanf("%d%d", &a, &b); a--; b--; g[a][i] = g[b][i] = true; } } void work() { if (uN > vN) { printf("NO\n"); return; } int ans = MaxMatch(); if (ans != uN) { printf("NO\n"); return; } if (yM[0] != -1) printf("%d", yM[0] + 1); else { int j = 0; while (!g[j][0]) j++; printf("%d", j + 1); } for (int i = 1; i < vN; i++) { if (yM[i] != -1) { printf(" %d", yM[i] + 1); continue; } int j = 0; while (!g[j][i]) j++; printf(" %d", j + 1); } } int main() { //freopen("t.txt", "r", stdin); int t; scanf("%d", &t); while (t--) { input(); work(); putchar('\n'); } return 0; }