二分图匹配 --- 最小点覆盖
来源:互联网 发布:手机智能机器人软件 编辑:程序博客网 时间:2024/05/16 06:18
//二分图有一个重要模型 – 最小点覆盖.
结论 : 最小点覆盖 = 二分图最大匹配数.
解释: 最小点覆盖指的是选择尽量少的点, 使得每条边至少有一个端点被选中. 那么在二分图匹配中很容易可以被证明就是该个二分图的最匹配数.
(把图画出来写一写就知道了.)
举几个例子 :
经典例题UVa – 11419
//题意: 在一个矩阵上某些位置上有一些目标, 每一次可以发射一颗子弹, 这颗子弹可以把任意一行或一列上的目标打完, 问最少需要几颗子弹, 并输出这些子弹发射的位置.
//思路 : 把每一行看做一个X结点, 每一列看做一个Y结点, 每个目标所在的位置对应的点有一条边, 这样, 子弹打掉所有的目标意味着每条边值得至少有一个结点被选中. 即可以从该点打出子弹可以清除该个目标, 这样最小点覆盖数就是答案, 跑一遍匈牙利就可以出答案了.
//但是麻烦的是还要输出打子弹的位置. 这个就比较难搞了. 白书上说的是什么匈牙利树, 不懂. 然后看了很多博客, 把代码仔细研究研究, 懂了. 大概就是从左边没有覆盖的点再找增广路, 并且这个未被覆盖的x点不管有无边, 我们最后都一定不会选它. 找到增广路后再从右边的那个点开始找, (此时找到的右边的那个点一定是匹配了的), 再找起增广路, 此时一定是还有的, 因为匹配了的, 这样我们我们可以发现右边的那个点连接着两个左边的点, 对应在图中肯定在该点处放子弹是最优的, 所以一直进行下去就可以找到所有最优的点, 然后输出就可以了.
AC Code
/** @Cain*/const int maxn=1e3+5;bool g[maxn][maxn];bool visx[maxn],visy[maxn];int linkx[maxn],linky[maxn];int n,m;bool dfs(int x){ visx[x] = true; for(int i=1;i<=m;i++){ if(visy[i] || !g[x][i]) continue; visy[i] = true; if(linky[i] == -1 || dfs(linky[i])){ linky[i] = x; linkx[x] = i; return true; } } return false;}void solve(){ int k; while(~scanf("%d%d%d",&n,&m,&k)){ if(n + m +k == 0) break; Fill(g,false); Fill(linkx,-1); Fill(linky,-1); for(int i=1;i<=k;i++){ int u,v; scanf("%d%d",&u,&v); g[u][v] = true; } int res = 0; for(int i=1;i<=n;i++){ Fill(visy,false); if(dfs(i)) res++; } printf("%d",res); /*这里就是checkx集合中的点。如果这个点被匹配了,先不管 然后就是check未匹配的点,不管有无其他点与其连接,这里都 显然不用放炮弹. 然后剩余的操作就是我说的那样*/ Fill(visx,false); Fill(visy,false); for(int i=1;i<=n;i++){ if(linkx[i] == -1) dfs(i); } bool flag = false; for(int i=1;i<=n;i++){ if(!visx[i]){ printf(" r%d",i); flag = true; } } if(flag) printf("\n"); flag = false; for(int i=1;i<=n;i++){ if(visy[i]){ printf(" c%d",i); flag = true; } } if(flag) printf("\n"); }}
福工OJ – 2573
//有了上面这道的基础, 这就是一道水题, 直接做.
AC Code
/** @Cain*/const int maxn=1e2+5;bool g[maxn][maxn],vis[maxn];int link[maxn];char a[maxn][maxn];int n,m;bool dfs(int x){ for(int i=1;i<=m;i++){ if(vis[i] || !g[x][i]) continue; vis[i] = true; if(link[i] == -1 || dfs(link[i])){ link[i] = x; return true; } } return false;}void solve(){ while(~scanf("%d",&n) && n){ scanf("%d",&m); Fill(g,false); Fill(link,-1); for(int i=1;i<=n;i++) scanf("%s",a[i]+1); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ int u = a[i][j]-'0'; if(u == 1) g[i][j] = true; } } int res = 0; for(int i=1;i<=n;i++){ Fill(vis,false); if(dfs(i)){ res++; } } printf("%d\n",res); }}
阅读全文
0 0
- 二分图匹配 + 最小点覆盖
- 二分图匹配 --- 最小点覆盖
- 二分图-最大匹配,最小路径覆盖,最小点覆盖
- 二分图最大匹配,最小点覆盖,最小路径覆盖,二分图最大独立集
- POJ 3692 最小点覆盖 最大二分图匹配
- hdu 1150 二分图 最小点覆盖=最大匹配
- HDU 1150 二分图匹配 最小点覆盖
- HDU 1150 二分图匹配 最小点覆盖
- poj 3041 二分图最大匹配(最小点覆盖问题)
- poj1463 二分图匹配的最小点覆盖
- hdu1150 二分图匹配的最小点覆盖
- hdu1498 二分图匹配(多次最小点覆盖)
- TOJ 1629 Muddy Fields -- 二分图匹配(最小点覆盖)
- hdu 2119 二分图匹配之最小点集覆盖
- HDU2119_Matrix(二分图/最小点覆盖=最大匹配)
- poj1325 Machine Schedule (最小点覆盖 二分图匹配)
- poj3041 Asteroids 最小点覆盖 二分图匹配
- hdu 1281 棋盘游戏(二分图匹配--最小点覆盖)
- 笔记8——Linux系统定时任务
- PHP基础之流程控制
- 前端代码规范
- HDU 6129 Just do it(找规律+杨辉三角)
- socket中recv() send() read() write()区别
- 二分图匹配 --- 最小点覆盖
- jdbc核心之事务
- thinkphp5学习笔记
- 2017.08.15工作日记
- hdu 6124 Euler theorem(水题)
- 4.高性能MySQL --- 服务器性能剖析( 2 )
- 排序--直接插入排序
- Hive QL[笔记4]
- mapreduce中的partitioner,combiner,shuffle