HDU1151—Air Raid(最小路径覆盖)
【】— (最小路径覆盖)
- 题解描述
给定一个(有向无环图),选定最少的点,使得从这些点出发可以覆盖每一条路径(即每个点都经过至少一遍)。
输入:
2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3
输出
2
1
以测试数据为例,个路口,条路。现派伞兵经过所有路口,求最少要派几名。
思路:
首先构建二分图,图的左边代表,右边也代表,若两点可行,则二分图中建边,求最少路径覆盖即为求最大独立集,也就是最大匹配数。
解释:
在二分图中,最小路径覆盖和最大独立集是等价的。
二分图是指一个图的顶点可以分为两个不相交的集合,并且图中的每条边都连接一个集合中的顶点和另一个集合中的顶点。
在二分图中,最小路径覆盖的解可以直接对应到最大独立集的解,反之亦然。具体来说,对于二分图中的最小路径覆盖问题,我们可以将其转化为最大独立集问题求解。而对于二分图中的最大独立集问题,我们也可以将其转化为最小路径覆盖问题求解。
这个等价关系的原因是,二分图的最大独立集正好对应着最小路径覆盖中选择的路径的起点和终点集合。因为在二分图中,任意两个相邻的顶点之间都没有边相连,所以选择一个顶点就意味着不选择与之相邻的顶点。
结论:二分图中最少路径覆盖即为最大独立集
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
/*
测试用例:
2
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3
答案:
2
1
*/
int match[N];
int st[N], g[N][N];
int n, m;
int dfs(int x) {
for (int i = 1; i <= n; i++) {
if (g[x][i] && !st[i]) {
st[i] = 1;
int t = match[i];
if (t == -1 || dfs(t)) {
match[i] = x;
return 1;
}
}
}
return 0;
}
int main() {
int T;
cin >> T; // T组测试数据
while (T--) {
cin >> n >> m; // n个节点,m条边
// 多组测试数据
memset(match, -1, sizeof match);
memset(g, 0, sizeof g);
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
g[a][b] = 1; // a->b,有向图
}
// 如果a->b,b->c,则 a->c,题意中说如果存在传递关系,需要我们建立关系清晰的边,也就是,
// 用 floyd,在O(N^3)的复杂度下完善点点之间的边关系
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] |= g[i][k] & g[k][j];
// 新图建成,开始跑匈牙利算法,求二分图的最大匹配
int cnt = 0;
for (int i = 1; i <= n; i++) {
memset(st, 0, sizeof st);
if (dfs(i)) cnt++;
}
// 二分图的最小点覆盖 = n- 二分图的最大匹配
printf("%d\n", n - cnt);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2019-07-31 牛B的大数据库
2018-07-31 新版本安装包需求汇总
2014-07-31 扩展自己的数组核心库
2014-07-31 关于小周同志在消息模块定位功能修改时存在的问题分析
2013-07-31 mina 和 xsocket