HDU 4619 —— Warm up 2(二分图最大匹配)
来源:互联网 发布:提督的决断 知乎 编辑:程序博客网 时间:2024/05/17 23:02
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4619
最近学了二分匹配,这块我是看kuangbin大神的文章的:http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657446.html
个人觉得他博客的文章很赞,很多总结也写得很好,强力推荐!
平面上有很多1X2的多米诺骨牌,横放或竖放,相同方向的不会重叠。现在要取走一些,使得剩下的两两没有重叠,问最多能剩下多少个。
有两种考虑的方法,一种是每块牌看作一个点,有重叠到的两块骨牌之间就连一条线,那么问题就是求最大独立集,最大独立集=总点数-最大匹配。
另一种就是将每个格点(每个骨牌占据两个格点)当作一个点,同一块骨牌覆盖到的格点就连一条线,那么问题就是对这些格点求一个最大匹配。
前者可以看作有N+M个点,后者最多是2*(N+M)个点。
但前者构图的时候每个骨牌都要去遍历另一种骨牌,构图的复杂度是O(NM),这种做法在kuangbin的博客上也有;
后者则只是在读入骨牌的时候直接构图,不用考虑其他骨牌,复杂度是O(N+M),但相对的后期处理的点就比较多,我采用的是这种;
对于每个坐标(x,y),因为0<=x<=100 ,0<=y<=100,所以每个坐标可以映射成一个数z=x*101+y
用一个f[z]来记录这块格点对应的编号,从1开始,因为N和M都不超过1000,所以覆盖到的最多4000个,如果不整理编号总共要101*101个点,但其中很多是空白的。
然后就是构图求最大匹配,最后的答案记得除以2。
二分匹配用的是Hopcroft-Carp算法。
#include<cstdio>#include<cstring>#include<vector>#include<queue>using namespace std;#define pb push_back#define maxn 4001const int inf = 0x7fffffff;inline void IN(int& x){ char c=getchar(); while(c<48 || c>57) c=getchar(); x=0; while(c>=48 && c<=57){ x=x*10+c-48; c=getchar(); }}vector<int> V[maxn];int n, dis;int f[20000];int dx[maxn], dy[maxn], Mx[maxn], My[maxn];bool vis[maxn];bool search(){ queue<int> Q; dis=inf; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=1; i<=n; i++){ if(Mx[i]==-1){ dx[i]=0; Q.push(i); } } while(!Q.empty()){ int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int i=0; i<V[u].size(); i++){ int j=V[u][i]; if(dy[j]!=-1) continue; dy[j] = dx[u]+1; if(My[j]==-1) dis=dy[j]; else{ dx[My[j]] = dy[j]+1; Q.push(My[j]); } } } return (dis!=inf);}bool dfs(int x){ for(int i=0; i<V[x].size(); i++){ int j= V[x][i]; if(vis[j] || dy[j]!=dx[x]+1) continue; vis[j]=1; if(My[j]!=-1 && dy[j]==dis) continue; if(My[j]==-1 || dfs(My[j])){ My[j]=x; Mx[x]=j; return 1; } } return 0;}int MaxMatch(){ int ans=0; memset(Mx,-1,sizeof(Mx)); memset(My,-1,sizeof(My)); while(search()){ memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++){ if(Mx[i]==-1 && dfs(i)) ans++; } } return ans;}int main(){ while(1){ int a, b, x, y, z1, z2; IN(a); IN(b); if(!(a||b)) break; memset(f,0,sizeof(f)); n=0; while(a--){ IN(x); IN(y); z1 = x*101+y; z2 = z1+101; if(!f[z1]){ f[z1]=++n; V[n].clear(); } z1 = f[z1]; if(!f[z2]){ f[z2]=++n; V[n].clear(); } z2 = f[z2]; V[z1].pb(z2); V[z2].pb(z1); } while(b--){ IN(x); IN(y); z1 = x*101+y; z2 = z1+1; if(!f[z1]){ f[z1]=++n; V[n].clear(); } z1 = f[z1]; if(!f[z2]){ f[z2]=++n; V[n].clear(); } z2 = f[z2]; V[z1].pb(z2); V[z2].pb(z1); } printf("%d\n", MaxMatch()>>1); } return 0;}
- hdu 4619 Warm up 2(二分图最大匹配)
- HDU 4619 —— Warm up 2(二分图最大匹配)
- hdu 4619 Warm up 2 ( 二分图最大匹配 )
- HDU 4619 Warm up 2(最大流或二分匹配)
- hdu 4619 Warm up 2[二分匹配]
- hdu 4619 Warm up 2 (二分匹配)
- hdu 4619 Warm up 2 (二分匹配)
- hdu 4619 Warm up 2【二分匹配】
- hdu Warm up 2( 二分图匹配)
- HDU-4619 Warm up 2 二分图匹配。
- HDU 4619-Warm up (二分图匹配)
- hdu4619 Warm up 2 二分图 最大匹配
- hdu 4619 Warm up 2 (二分图最大独立集)
- HDU 4619 Warm up 2(贪心、并查集 | 二分图最大独立集)
- HDU 4619 Warm up 2 最大匹配数
- hdu 4619 Warm up 2 (二分图)
- hdu_4619 Warm up 2 二分图匹配
- Warm up 2(hdu4619,二分匹配)
- LinuxCast学习笔记二十五:Service_Basic
- 编译Android4.4系统总结
- Application.Current的使用
- 打印链表
- .net 调用Oracle存储过程
- HDU 4619 —— Warm up 2(二分图最大匹配)
- spring、struct、hibernate三大框架整合--扩展一:添加ajax的支持
- 黑马程序员---面向对象
- 使用邮箱地址标识用户
- linux 共享内存
- 黑马程序员 C#学习笔记③ ADO.NET实现登录案例
- 全屏自适应背景图
- windows下的oracle 如何生成awr报告
- Kinect for windows 1.0 vs Kinect for windows 2.0