二分图匹配 POJ2195
来源:互联网 发布:廊坊百度快照优化推广 编辑:程序博客网 时间:2024/05/17 03:29
POJ2195 给出二分图,求最小费用的最佳匹配。
我们把费用取相反数,求一次最大匹配就可以了。KM算法必须要保证n==m。
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>using namespace std;#define INF 0x3f3f3f3f#define Maxn 120struct Node{int x,y;}g[Maxn],h[Maxn];int map[Maxn][Maxn],match[Maxn],slack[Maxn],lx[Maxn],ly[Maxn];bool visx[Maxn],visy[Maxn];char st[Maxn][Maxn];int N,M,n,m;int abs(int x){if (x<0) x=-x;return x;}int Dis(Node a,Node b){return abs(a.x-b.x)+abs(a.y-b.y);}void init(){memset(map,0,sizeof(map));n=m=0;for (int i=1;i<=N;i++){scanf("%s",st[i]+1);st[i][0]='~';for (int j=1;j<=M;j++){if (st[i][j]=='m'){n++;g[n].x=i;g[n].y=j;}if (st[i][j]=='H'){m++;h[m].x=i;h[m].y=j;}}}for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){map[i][j]=-Dis(g[i],h[j]);}}}bool dfs(int i){visx[i]=true;for (int j=1;j<=m;j++){int tmp=lx[i]+ly[j]-map[i][j];if (visy[j]) continue;if (tmp==0){visy[j]=true;if (match[j]==-1|| dfs(match[j])){match[j]=i;return true;}}else if (tmp<slack[j]){slack[j]=tmp;}}return false;}int KM(){memset(match,-1,sizeof(match));//memset(lx,0,sizeof(lx));memset(ly,0,sizeof(ly));for (int i=1;i<=n;i++){lx[i]=-INF;for (int j=1;j<=m;j++){if (lx[i]<map[i][j]) lx[i]=map[i][j];}}for (int k=1;k<=n;k++){for (int i=1;i<=n;i++) slack[i]=INF;while(1){memset(visx,false,sizeof(visx));memset(visy,false,sizeof(visy));if (dfs(k)) break;int dx=INF;for (int i=1;i<=m;i++){if (!visy[i]&&dx>slack[i]) dx=slack[i];}for (int i=1;i<=n;i++){if (visx[i]) lx[i]-=dx;}for (int i=1;i<=m;i++){if (visy[i]) ly[i]+=dx;else slack[i]-=dx;}}}int ret=0;for (int i=1;i<=m;i++)ret+=map[match[i]][i];return -ret;}int main(){while (~scanf("%d%d",&N,&M),N||M){init();int ans=KM();printf("%d\n",ans);}return 0;}
还有一种做法,slack实际上相当于只要取一个最小值就可以了。我们可以省略这个数组,代码也稍微短一点。
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>using namespace std;#define INF 0x3f3f3f3f#define Maxn 120struct Node{int x,y;}g[Maxn],h[Maxn];int map[Maxn][Maxn],match[Maxn],lx[Maxn],ly[Maxn];bool visx[Maxn],visy[Maxn];char st[Maxn][Maxn];int N,M,n,m,slack;int abs(int x){if (x<0) x=-x;return x;}int Dis(Node a,Node b){return abs(a.x-b.x)+abs(a.y-b.y);}void init(){memset(map,0,sizeof(map));n=m=0;for (int i=1;i<=N;i++){scanf("%s",st[i]+1);st[i][0]='~';for (int j=1;j<=M;j++){if (st[i][j]=='m'){n++;g[n].x=i;g[n].y=j;}if (st[i][j]=='H'){m++;h[m].x=i;h[m].y=j;}}}for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){map[i][j]=-Dis(g[i],h[j]);}}}bool dfs(int i){visx[i]=true;for (int j=1;j<=m;j++){int tmp=lx[i]+ly[j]-map[i][j];if (visy[j]) continue;if (tmp==0){visy[j]=true;if (match[j]==-1|| dfs(match[j])){match[j]=i;return true;}}else if (tmp<slack){slack=tmp;}}return false;}int KM(){memset(match,-1,sizeof(match));//memset(lx,0,sizeof(lx));memset(ly,0,sizeof(ly));for (int i=1;i<=n;i++){lx[i]=-INF;for (int j=1;j<=m;j++){if (lx[i]<map[i][j]) lx[i]=map[i][j];}}for (int k=1;k<=n;k++){while(1){memset(visx,false,sizeof(visx));memset(visy,false,sizeof(visy));slack=INF;if (dfs(k)) break;int dx=slack;for (int i=1;i<=n;i++){if (visx[i]) lx[i]-=dx;if (visy[i]) ly[i]+=dx;}}}int ret=0;for (int i=1;i<=m;i++)ret+=map[match[i]][i];return -ret;}int main(){while (~scanf("%d%d",&N,&M),N||M){init();int ans=KM();printf("%d\n",ans);}return 0;}
0 0
- 二分图匹配 POJ2195
- 【poj2195】【二分图最佳匹配】Going Home
- 二分图匹配KM算法 POJ2195
- poj2195 二分图的最佳匹配
- POJ2195 Going Home【二分图最佳匹配】
- poj2195 二分图带权最小匹配
- POJ2195 Going Home 【最小费用流】+【二分图最佳匹配】
- poj2195 Going Home(二分图的最小权匹配)
- poj2195(二分图最大匹配,最小费用流)
- 二分图相关概念 二分图最大匹配 二分图最大权匹配 poj3041 poj2195
- poj2195最小权值二分匹配KM算法
- POJ2195 最佳匹配
- poj2195 bfs+最小权匹配
- poj2195
- poj2195
- poj2195
- poj2195
- poj2195
- Codeforces Round #273 (Div. 2) --A Initial Bet
- oracle_001
- 从今天开始写博客
- 从不断更新query日志的字符串流中随机选择一个字符串?10000个字符串呢?
- Android教程-从零开始一步一步接入SDK
- 二分图匹配 POJ2195
- numa
- oracle regexp_replace函数
- C++中引用(&)的用法和应用实例
- IOS开发之__bridge,__bridge_transfer和__bridge_retained
- CFH
- maven上传jar到私服
- searchBa牛逼文档
- UITableView 一直显示滚动条(ScrollBar Indicators)、滚动条Width(宽度)、滚动条Color(颜色)