poj1422

题意:给定一个有向无环图,在这个图上的某些点上放伞兵,可以使伞兵可以走到图上所有的点。且每个点只被一个伞兵走一次。问至少放多少伞兵。

分析:最小路径覆盖。我们可以把问题转化为,在图上的边中选出一些边,使得每个点的入度与出度都不超过1。

我们开始在图上的每个点都放上伞兵,然后没选出一条边,就意味着有一个伞兵可以被取消掉了。也就是说需要的最少伞兵数=点总数-能选出的最大边数。

我们只要求最大边数即可。用二分图匹配,把每个点拆成两个点,分别加入二分图的两个点集,原图中一条由a到b的边在二分图中是一条由第一个点集中的第a个点到第二个点集中的第b个点。也就是第一个点集的点与出边有关,第二个与入边有关。匹配时也就保证了每个点的入度与出度都不超过1。求最大匹配即为能选出的最大边数。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
usingnamespace std;

#define maxn 150

int uN, vN;
bool g[maxn][maxn];
int xM[maxn], yM[maxn];
bool chk[maxn];
int n, m;

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;
returntrue;
}
}
returnfalse;
}

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()
{
memset(g,
0, sizeof(g));
scanf(
"%d%d", &n, &m);
uN
= vN = n;
for (int i =0; i < m; i++)
{
int a, b;
scanf(
"%d%d", &a, &b);
a
--;
b
--;
g[a][b]
=true;
}
}

int main()
{
// freopen("t.txt", "r", stdin);
int t;
scanf(
"%d", &t);
while (t--)
{
input();
int ans = n - MaxMatch();
printf(
"%d\n", ans);
}
return0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2083578.html