题意:给定一个有向无环图,在这个图上的某些点上放伞兵,可以使伞兵可以走到图上所有的点。且每个点只被一个伞兵走一次。问至少放多少伞兵。
分析:最小路径覆盖。我们可以把问题转化为,在图上的边中选出一些边,使得每个点的入度与出度都不超过1。
我们开始在图上的每个点都放上伞兵,然后没选出一条边,就意味着有一个伞兵可以被取消掉了。也就是说需要的最少伞兵数=点总数-能选出的最大边数。
我们只要求最大边数即可。用二分图匹配,把每个点拆成两个点,分别加入二分图的两个点集,原图中一条由a到b的边在二分图中是一条由第一个点集中的第a个点到第二个点集中的第b个点。也就是第一个点集的点与出边有关,第二个与入边有关。匹配时也就保证了每个点的入度与出度都不超过1。求最大匹配即为能选出的最大边数。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include
<
iostream
>
#include < cstdio >
#include < cstdlib >
#include < cstring >
using namespace 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;
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()
{
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);
}
return 0 ;
}
#include < cstdio >
#include < cstdlib >
#include < cstring >
using namespace 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;
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()
{
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);
}
return 0 ;
}