带权二分图匹配KM算法
来源:互联网 发布:知乎 正装西服品牌 编辑:程序博客网 时间:2024/05/22 00:23
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int INF=1e9;int flag;struct zp{ int x,y;}man[200],house[200];int x[200][200],mn,ho,lx[200],ly[200];void build_map()//建图,单向图{ for(int i=0; i<mn; i++) { for(int j=0; j<ho; j++) { x[i+1][j+1]=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y); } }}int visx[200],visy[200],dis[200],ans;int dfspath(int k)//匈牙利算法,寻找路径{ visx[k]=1; for(int i=1; i<=mn; i++) { if(!visy[i]&&lx[k]+ly[i]==x[k][i]) { visy[i]=1; if(dis[i]==-1||dfspath(dis[i])) { dis[i]=k; return 1; } } } return 0;}int KM(){ if(!flag)//最小权值处理 { for(int i=1;i<=mn;i++) for(int j=1;j<=ho;j++) x[i][j]=-x[i][j]; } for(int i=1;i<=mn;i++)//初始化x点集标号 { lx[i]=x[i][1]; for(int j=2;j<=ho;j++) lx[i]=max(lx[i],x[i][j]); } memset(ly,0,sizeof(ly));//初始化y点集标号 memset(dis,-1,sizeof(dis));//保存对应关系 for(int i=1; i<=mn; i++) { while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(dfspath(i))//找到路径 break; int Min=INF+1; for(int j=1;j<=mn;j++)//扩大子图范围 { if(visx[j]) for(int k=1;k<=ho;k++) if(!visy[k]) Min=min(Min,lx[j]+ly[k]-x[j][k]); } for(int j=1;j<=mn;j++)//更新x点集标号 if(visx[j]) lx[j]-=Min; for(int j=1;j<=ho;j++)//更新y点集标号 if(visy[j]) ly[j]+=Min; } } ans=0; for(int i=1;i<=ho;i++)//计算权值和1 ans+=x[dis[i]][i]; if(!flag)//求最小权值 ans=-ans; return ans;//返回权值}int main(){ int n,m; while(~scanf("%d%d",&n,&m)&&(n||m)) { mn=ho=0; char a[200]; memset(x,0,sizeof(x)); //flag=1;//最大权匹配 flag=0;//最小权匹配 ,把权值取反然后求最大权匹配然后把结果取反 for(int i=0; i<n; i++) { scanf("%s",a); for(int j=0; j<m; j++) { if(a[j]=='m') man[mn].x=i+1,man[mn++].y=j+1; else if(a[j]=='H') house[ho].x=i+1,house[ho++].y=j+1; } } build_map(); printf("%d\n",KM()); }}
上面题目链接
题目大概意思是让求所有的m到H走的所有路之和最小,每一个H只能承载1个m。
KM的一点优化,有两种方式
hdu 2255题目
一般解法:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int INF=1e9;int flag;int x[500][500],n,lx[500],ly[500];int visx[500],visy[500],dis[500],ans;int dfspath(int k)//匈牙利算法,寻找路径{ visx[k]=1; for(int i=0; i<n; i++) { if(!visy[i]&&lx[k]+ly[i]==x[k][i]) { visy[i]=1; if(dis[i]==-1||dfspath(dis[i])) { dis[i]=k; return 1; } } } return 0;}int KM(){// if(!flag)//最小权值处理// {// for(int i=0;i<=n;i++)// for(int j=0;j<n;j++)// x[i][j]=-x[i][j];// } memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly));//初始化y点集标号 memset(dis,-1,sizeof(dis));//保存对应关系 for(int i=0; i<n; i++) //初始化x点集标号 for(int j=0; j<n; j++) lx[i]=max(lx[i],x[i][j]); for(int i=0; i<n; i++) { while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(dfspath(i))//找到路径 break; int Min=INF+1; for(int j=0; j<n; j++) //扩大子图范围 { if(visx[j]) for(int k=0; k<n; k++) if(!visy[k]) Min=min(Min,lx[j]+ly[k]-x[j][k]); } for(int j=0; j<n; j++) //更新x,y点集标号 { if(visx[j]) lx[j]-=Min; if(visy[j]) ly[j]+=Min; } } } ans=0; for(int i=0; i<n; i++) //计算权值和1 ans+=x[dis[i]][i];// if(!flag)//求最小权值// ans=-ans; return ans;//返回权值}int main(){ while(~scanf("%d",&n)) { //flag=1;//最大权匹配 //flag=0;//最小权匹配 ,把权值取反然后求最大权匹配然后把结果取反 for(int i=0; i<n; i++) for(int j=0; j<n; j++) scanf("%d",&x[i][j]); //build_map(); printf("%d\n",KM()); }}
优化后的:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int INF=1e9;int flag;int x[500][500],n,lx[500],ly[500];int visx[500],visy[500],dis[500],ans,slack[500],Min;void build_map()//建图,单向图{}int dfspath(int k)//匈牙利算法,寻找路径{ visx[k]=1; for(int i=0; i<n; i++) { if(visy[i]) continue; int t=lx[k]+ly[i]-x[k][i]; if(t==0) { visy[i]=1; if(dis[i]==-1||dfspath(dis[i])) { dis[i]=k; return 1; } } else //slack[i]=min(slack[i],t);//优化1 Min=min(Min,t);//优化2 } return 0;}int KM(){// if(!flag)//最小权值处理// {// for(int i=0; i<n; i++)// for(int j=0; j<n; j++)// x[i][j]=-x[i][j];// } memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly));//初始化y点集标号 memset(dis,-1,sizeof(dis));//保存对应关系 for(int i=0; i<n; i++) //初始化x点集标号 for(int j=0; j<n; j++) lx[i]=max(lx[i],x[i][j]); for(int i=0; i<n; i++) {// for(int j=0;j<=n;j++)//优化1// slack[j]=INF; while(1) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); Min=INF+1; if(dfspath(i))//找到路径 break;// for(int j=0; j<n; j++)//扩大子图范围 优化1 优化2不要这一步// if(!visy[j])// Min=min(Min,slack[j]); for(int j=0; j<n; j++) //更新x点集标号 { if(visx[j]) lx[j]-=Min; if(visy[j]) ly[j]+=Min;// else//有这一步会超时,但是有的人博客上有这一步,参考下// slack[i]-=Min; } } } ans=0; for(int i=0; i<n; i++) //计算权值和 ans+=x[dis[i]][i];// if(!flag)//求最小权值// ans=-ans; return ans;//返回权值}int main(){ while(~scanf("%d",&n)) { flag=1; for(int i=0; i<n; i++) for(int j=0; j<n; j++) scanf("%d",&x[i][j]); printf("%d\n",KM()); }}
0 0
- 带权二分图匹配KM算法
- KM算法--带权二分匹配
- 带权的二分图的最优匹配KM算法
- 带权二分图最佳匹配KM算法模板
- 带权二分图的最佳匹配(KM算法)
- KM算法--带权二分图最佳匹配
- 带权二分匹配——KM算法
- 算法模板之KM(带权的二分匹配)
- 二分图匹配【KM算法】
- KM算法——带权二分图最佳匹配问题
- KM(带权最大二分匹配) 模板
- POJ 2195 二分图最小权匹配KM算法
- KM算法 二分图的最佳匹配
- 【二分图最大权匹配---KM算法】
- 二分图的最佳匹配(KM 算法)
- 带权值的二分图匹配 KM算法
- 二分图最大权匹配 (KM算法)
- KM算法求二分图最优匹配
- ActiveMQ常见错误
- Shell脚本一键启动/关闭 zookeeper集群(版本1.1)
- Apache 启动、停止、重启命令
- 【MySQL】关于 unauthenticated user的哲学思考
- Context namespace element 'component-scan' and its parser class [org.springframework.context.annotat
- 带权二分图匹配KM算法
- 架构 - 第二课:git命令
- java集合08--List总结
- 【codevs1098 均分纸牌】贪心
- 查看应用的安全码
- java工程连接数据库(数据源dbcp/c3p0)
- 对MVC、MVP、MVVM的理解
- 详谈javascript中document.referrer的兼容性
- TensorFlow中cnn-cifar10样例代码详解