poj1719

二分图匹配

题意:给定一个r*c的棋盘,其中每列有2个白色格子,其余为黑色。要求选出c个白色格子,且每列一个,且每行至少一个。问能否实现,给出方案。

分析:如果r>c则必定无法满足,因为即使每列一个,均位于不同行,还是会有某些行没有被选中的格子。对于其余情况,先进行简单的二分图匹配(每行作为1点构成第一点集,每列作为1点构成第二点集,每个白色格子作为连接其行列点的边),如果每行都能匹配上则首先可以保证每行都有选中的格子,当然此时可能有一些列还有没有被选中的格子,只要在该列里随便选1个白的就行了,不会影响结果。

View Code
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
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;
}
posted @ 2011-09-29 21:41  金海峰  阅读(359)  评论(0编辑  收藏  举报