参考博客
最小路径覆盖:在一个有向图中,找出最少的路径,使得这些路径经过了所有的点。
最小路径覆盖分为最小不相交路径覆盖和最小可相交路径覆盖。
最小不相交路径覆盖:每一条路径经过的顶点各不相同。
最小可相交路径覆盖:每一条路径经过的顶点可以相同。
特别的,每个点自己也可以称为是路径覆盖,只不过路径的长度是0。
【DAG的最小不相交路径覆盖】HDU 1151 Air Raid
Problem Description
给你n个城市,m条有向的道路,每个伞兵起始点可以是任何一个城市,伞兵之间不能走相同的城市。问你至少需要多少个伞兵,可以把所有的城市都覆盖到。
思路:
把原图的每个点拆成vx 和 vy两个点,如果有一条有向边A->B,那么就加边Ax−>By。这样就得到了一个二分图。那么最小路径覆盖=原图的结点数-新图的最大匹配数。
新图的最大匹配数 = 原图出点或入点没有公共端点的最大边集合
#include<bits/stdc++.h>
using namespace std;
#define nn 130
vector<int> Map[nn];
int n, vis[nn], match[nn];
bool dfs(int u)
{
for(int i = 0; i < Map[u].size(); i++)
{
int to = Map[u][i];
if(!vis[to])
{
vis[to] = 1;
if(!match[to] || dfs(match[to]))
{
match[to] = u;
return 1;
}
}
}
return 0;
}
int solve()
{
memset(match, 0, sizeof(match));
int ans = 0;
for(int i = 1; i <= n; i++)//求最大匹配数
{
memset(vis, 0, sizeof(vis));
if(dfs(i)) ans++;
}
return ans;
}
void add(int u, int v)
{
Map[u].push_back(v);
}
int main()
{
int T, i, m, u, v;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &m);
for(i = 0; i <= n; i++) Map[i].clear();
while(m--)
{
scanf("%d %d", &u, &v);
add(u, v);
}
printf("%d\n", n - solve());//最小路径覆盖=原图的结点数-原图出点或入点没有公共端点的最大边集合
}
return 0;
}
【DAG的最小可相交路径覆盖】POJ 2594 Treasure Exploration
Problem Description
在外星上有n个点需要机器人去探险,有m条单向路径。问至少需要几个机器人才能遍历完所有的点,一个点可以被多个机器人经过(这就是和单纯的最小路径覆盖的区别)。
思路:
先用floyd求出原图的传递闭包,即如果a到b有路径,那么就加边a->b。然后就转化成了最小不相交路径覆盖问题。
至于为什么,只能自己画图理解,不知如何表达出来
#include<cstdio>
#include<cstring>
using namespace std;
#define nn 550
int Map[nn][nn];
int n, vis[nn], match[nn];
bool dfs(int u)
{
for(int i = 1; i <= n; i++)
{
if(!vis[i] && Map[u][i])
{
vis[i] = 1;
if(!match[i] || dfs(match[i]))
{
match[i] = u;
return 1;
}
}
}
return 0;
}
int solve()
{
memset(match, 0, sizeof(match));
int ans = 0;
for(int i = 1; i <= n; i++)
{
memset(vis, 0, sizeof(vis));
if(dfs(i)) ans++;
}
return ans;
}
void Floyd()
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
for(int k = 1; k <= n; k++)
{
if(Map[i][k] && Map[k][j])
{
Map[i][j] = 1;
}
}
}
}
}
int main()
{
int m, u, v;
while(~scanf("%d %d", &n, &m) && n+m)
{
memset(Map, 0, sizeof(Map));
while(m--)
{
scanf("%d %d", &u, &v);
Map[u][v] = 1;
}
Floyd();//求传递闭包
printf("%d\n", n - solve());
}
return 0;
}