KM(带权最大二分匹配) 模板
来源:互联网 发布:黎明杀机刷血点软件 编辑:程序博客网 时间:2024/05/17 07:19
板子:
const int maxn=300+5;int g[maxn][maxn];int link[maxn],lx[maxn],ly[maxn];bool visx[maxn],visy[maxn];int nx,ny,d;bool Find(int x){ visx[x] = true; for(int i=1;i<=ny;i++){ if(visy[i]) continue; int tmp = lx[x] + ly[i] - g[x][i]; if(!tmp){ visy[i] = true; if(link[i] == -1 || Find(link[i])){ link[i] = x; return true; } } else d=min(d,tmp); } return false;}int KM(){ Fill(link,-1); Fill(ly,0); Fill(lx,0); for(int i=1;i<=nx;i++){ for(int j=1;j<=ny;j++){ if(g[i][j] > lx[i]) lx[i] = g[i][j]; } } for(int i =1 ; i<= nx;i++){ while(true){ Fill(visx,false); Fill(visy,false); d = inf; if(Find(i)) break; if(d == inf) return -1; for(int j = 1 ; j<=nx ; j++) if(visx[j]) lx[j] -= d; for(int j = 1 ; j<=ny ; j++) if(visy[j]) ly[j] += d; } } int res = 0; for(int i=1;i<=ny;i++){ if(link[i] != -1) res += g[link[i]][i]; } return res;}void solve(){ int n; while(~scanf("%d",&n)){ Fill(g,0); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&g[i][j]); } } nx = ny = n; int res = KM(); printf("%d\n",res); }}
模板题
基于这道题
const int maxn=300+5;int g[maxn][maxn]; //二分图表示.int link[maxn],lx[maxn],ly[maxn]; //y的匹配关系. x,y的标杆状态.bool visx[maxn],visy[maxn];int nx,ny,d; //两边的点数. 以及需要寻找的最小的d.bool Find(int x){ visx[x] = true; for(int i=1;i<=ny;i++){ if(visy[i]) continue; int tmp = lx[x] + ly[i] - g[x][i]; if(!tmp){ //tmp=0表示在当前图匹配了的边, 即看现在匹配是否合理, visy[i] = true; if(link[i] == -1 || Find(link[i])){ link[i] = x; return true; } } else d=min(d,tmp); //就是在S集合中的x,和不在T集合中的y找一个最小的d. } return false;}int KM(){ Fill(link,-1); Fill(ly,0); Fill(lx,0); for(int i=1;i<=nx;i++){ for(int j=1;j<=ny;j++){ if(g[i][j] > lx[i]) lx[i] = g[i][j]; } } for(int i =1 ; i<= nx;i++){ while(true){ Fill(visx,false); Fill(visy,false); d = inf; if(Find(i)) break; //若成功(找到了增广轨),则该点增广完成,进入下一个点的增广 //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。 //方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d, //所有在增广轨中的Y方点的标号全部加上一个常数d // if(d == inf) return -1; //如果可以确定左边的点都会被匹配完,则就可以不用加这条语 //句. 如果不能就要加上这句话. (所以一般在题目中给了一定完美匹配的话,就可以不用这句话) //而有些题目会问你是否是完美匹配,不是的话输出-1,是的话在输出答案,所以这个时候就要加上这句话. //大多数题目是可以不用加的. for(int j = 1 ; j<=nx ; j++) if(visx[j]) lx[j] -= d; for(int j = 1 ; j<=ny ; j++) if(visy[j]) ly[j] += d; } } int res = 0; for(int i=1;i<=ny;i++){ // if(link[i] != -1) //这些都根据题意来加. res += g[link[i]][i]; } return res;} //这道题是保证了一定有最大二分匹配的!!! 所以一些东西可以去掉.void solve(){ int n; while(~scanf("%d",&n)){ Fill(g,0); //找最大所以初始化为较小的值. 这样一减就会很小了. for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&g[i][j]); } } nx = ny = n; int res = KM(); printf("%d\n",res); }}
//这个模型还是比较好看出来, 就是建图时要多想想!
记一下几种转换 : (好好想想)
最小权值匹配, 取反 (所有的边权取反,即取成负的边,最后答案再添个负号就行了,其他步骤一样)没有完备匹配,赋0边权之积最大,取对数(对数相加 就等于指数相乘嘛)
阅读全文
0 0
- KM(带权最大二分匹配) 模板
- 带权二分图最佳匹配KM算法模板
- 算法模板之KM(带权的二分匹配)
- 【模板】KM算法模板(带注释)——二分图带权最大匹配
- KM算法--带权二分匹配
- 带权二分图匹配KM算法
- hdu3722Card Game(KM最大带权匹配)
- hdu3722Card Game(KM最大带权匹配)
- 带权的二分图的最优匹配KM算法
- hdu_2255_奔小康赚大钱(KM带权二分匹配板子)
- 带权二分图的最佳匹配(KM算法)
- KM算法--带权二分图最佳匹配
- 带权二分匹配——KM算法
- HDU 2255 奔小康赚大钱(二分图的最大带权匹配 裸的KM算法)
- HDU 2255 带权二分图 KM模板
- 图论 二分图 hdu1533 KM最大匹配
- 二分图最大匹配(匈牙利KM)
- hdu2255二分最优匹配KM标准模板
- 百练noi18:肿瘤面积
- KAFKA知识(zk中架构图)
- 拼多多算法工程师笔试题之分配巧克力
- (本人stm32f03)配置系统时钟时,需要注意flash等待周期数要和系统时钟频率对应,不然程序跑飞
- Fragment生命周期探究
- KM(带权最大二分匹配) 模板
- Eclipse+Maven创建webapp项目
- 在Android framework层启动服务不被杀掉
- 【Docker系列】——解决Docker容器时间与主机不一致问题
- Android源码开发小案例
- ORACLE函数以及存储过程学习篇
- ANSYS 添加PCB板材料 FR-4
- GANs学习系列(9):DCGAN对抗卷积神经网络总结
- 瑞萨单片机解调好盈电调控制无刷电机