求二分图最大匹配的两种算法
来源:互联网 发布:php短信接口 编辑:程序博客网 时间:2024/05/17 04:10
这里以TJOI2016的游戏为例
Description
在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。
给定一张n ∗ m的网格地图:
其中∗代表空地,炸弹的威力可以穿透,可以在空地上放置一枚炸弹。
x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。
#代表硬石头,炸弹的威力是不能穿透的,不能在此放置炸弹。
例如:给出1∗4的网格地图∗xx∗,这个地图上最多只能放置一个炸弹。给出另一个1 ∗ 4的网格地图∗x#∗,这个地图最多能放置两个炸弹。
现在小H任意给出一张n ∗ m的网格地图,问你最多能放置多少炸弹。
Input
第一行输入两个正整数n,m,n表示地图的行数,m 表示地图的列数。1 ≤
n,m ≤ 50。
接下来输入n行m列个字符,代表网格地图。
Output
输出一个整数a,表示最多能放置炸弹的个数。
Sample Input
4 4
#***
*#**
**#*
xxx#
Sample Output
5
对于本题的分析可以看一下这里
对于二分图最大匹配,有两种较实用的方法:一种是转化成最大流问题求解,一种是匈牙利算法。
先讲第一种吧。如何将二分图转化为最大流问题?其实很容易,不妨对二分图作如下变形。
将原图中的所有无向边
新得到的图G’中s-t的最大流就是原二分图G中最大匹配的匹配数,而
#include<stdio.h>#include<string.h>#include<vector>#include<algorithm>#include<iostream>#define oo 2000000000#define M 55using namespace std;template <class T>inline void Rd(T &res){ char c;res=0;int k=1; while(c=getchar(),c<48&&c!='-'); if(c=='-'){k=-1;c='0';} do{ res=(res<<3)+(res<<1)+(c^48); }while(c=getchar(),c>=48); res*=k;}int used[M*M];struct edge{ int to,cap,rev;};vector<edge>G[M*M];void add_edge(int u,int v,int cap){ G[u].push_back((edge){v,cap,G[v].size()}); G[v].push_back((edge){u,0,G[u].size()-1});}int dfs(int s,int t,int f){ if(s==t)return f; used[s]=1; for(int i=0;i<G[s].size();i++){ edge &e=G[s][i]; if(!used[e.to]&&e.cap>0){ int d=dfs(e.to,t,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } }}int max_flow(int s,int t){ int flow=0; while(1){ memset(used,0,sizeof(used)); int f=dfs(s,t,oo); if(f==0)return flow; flow+=f; }}int n,m;int row[M][M],col[M][M];int rowid[M*M],colid[M*M];int R,C;char map[M][M];int main(){ Rd(n);Rd(m); for(int i=1;i<=n;i++) scanf("%s",map[i]+1); R=1,C=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(map[i][j]!='#'&&!row[i][j]){ for(int k=j;k<=m&&map[i][k]!='#';k++)row[i][k]=R; R++; } if(map[i][j]!='#'&&!col[i][j]){ for(int k=i;k<=n&&map[k][j]!='#';k++)col[k][j]=C; C++; } } for(int i=1;i<R;i++)rowid[i]=i;//将横块编号为1~R-1 for(int i=1;i<C;i++)colid[i]=i+R-1;//将竖块编号为R~R+C-2 int s=0;//将s编号为0 int t=R+C-1;//将t编号为R+C-1 for(int i=1;i<R;i++)add_edge(s,rowid[i],1); for(int i=1;i<C;i++)add_edge(colid[i],t,1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='*'&&row[i][j]&&col[i][j])add_edge(rowid[row[i][j]],colid[col[i][j]],1); printf("%d\n",max_flow(s,t)); return 0;}
匈牙利算法,用来二分图匹配很简单。
#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>#define M 55using namespace std;template <class T>inline void Rd(T &res){ char c;res=0;int k=1; while(c=getchar(),c<48&&c!='-'); if(c=='-'){k=-1;c='0';} do{ res=(res<<3)+(res<<1)+(c^48); }while(c=getchar(),c>=48); res*=k;}int used[M*M];int n,m;int row[M][M],col[M][M];int rowid[M*M],colid[M*M];int g[M*M][M*M],match[M*M];int R,C,ans;bool dfs(int x){ for(int i=1;i<C;i++) if(g[x][colid[i]]&&!used[colid[i]]){ used[colid[i]]=1; if(match[colid[i]]==-1||dfs(match[colid[i]])){ match[colid[i]]=x; return true; } } return false;}char map[M][M];int main(){ Rd(n);Rd(m); for(int i=1;i<=n;i++) scanf("%s",map[i]+1); R=1,C=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(map[i][j]!='#'&&!row[i][j]){ for(int k=j;k<=m&&map[i][k]!='#';k++)row[i][k]=R; R++; } if(map[i][j]!='#'&&!col[i][j]){ for(int k=i;k<=n&&map[k][j]!='#';k++)col[k][j]=C; C++; } } for(int i=1;i<R;i++)rowid[i]=i;//将横块编号为1~R-1 for(int i=1;i<C;i++)colid[i]=i+R-1;//将竖块编号为R~R+C-21 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='*') g[rowid[row[i][j]]][colid[col[i][j]]]=1; memset(match,-1,sizeof(match)); for(int i=1;i<R;i++){ memset(used,0,sizeof(used)); if(dfs(rowid[i]))ans++; } printf("%d\n",ans); return 0;}
- 求二分图最大匹配的两种算法
- 二分图的两种算法-最大匹配与最优匹配 poj--1469,2536
- 匈牙利算法 求二分图最大匹配
- 匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- (转载)用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 匈牙利算法求二分图的最大匹配
- 用匈牙利算法求二分图的最大匹配
- 匈牙利算法求二分图的最大匹配
- 匈牙利算法求二分图的最大匹配
- 【NOIP2009】洛谷1070 道路游戏
- DNS解析问题详解!
- 【CUDA自带实例学习】2.锁页内存
- 1111
- spring cloud 1:Spring Cloud和dubbo对比
- 求二分图最大匹配的两种算法
- Web移动端设备适配
- 清除浮动
- nohup命令在linux系统,控制jar包后台运行
- Android进行设备管理(针对企业开发)
- android自定义字体
- Spring对于赋值Xml赋值方式
- latex的参考文献
- 最全的国内外IT学习网站和工具(自己总结的)