hdu 2853 Assignment KM好题
来源:互联网 发布:洲际巡航导弹知乎 编辑:程序博客网 时间:2024/05/23 15:40
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2853
刚开始读这个题目时,就感觉不太好解决。放了好几天,于是水了一发,愉快地过了样例,然后交上去,当然愉快地WA,想了一下,实在没什么好的解决思路,就百度了一发,思路来自百度。。。
因为我们要变动最小,所以对在原计划中的边要有一些特殊照顾,使得最优匹配时,尽量优先使用原计划的边,这样变化才能是最小的且不会影响原匹配。
根据这个思想,我们可以把每条边的权值扩大k倍,k要大于n。然后对原计划的边都+1。精华全在这里。我们来详细说明一下。
全部边都扩大了k倍,而且k比n大,这样,我们求出的最优匹配就是k倍的最大权值,只要除以k就可以得到最大权值。实现原计划的边加1,这样,在每次选择边时,这些变就 有了优势,就会优先选择这些边。假如原计划的h条边被选入了最优匹配中,这样,最优权值就是k倍的最大权值+h(原计划的每条边都+1)。但是k大于n的用意何在呢?我们发现假如原计划的边全部在匹配中,只会增加n,又n<k,所以除以k后不会影响最优匹配的最大权值之和,然后我们对k取余,就正好得到加入的原计划的边的个数。这时,我们只需要用总点数-加入的原计划的点数,就可以求得最小变动数了。
有了思路,代码就很简单了,不得不感叹一下思路的巧妙。最后,人傻就要多努力
#include <iostream>#include <string>#include <cstdio>#include <algorithm>#include <cstring>#include <cctype>#include <vector>#include <cmath>using namespace std;const int N = 60;const int INF = 0x3f3f3f3f;int n, nx, ny;int lx[N], ly[N], slack[N], match[N], s[N][N];bool visx[N], visy[N];bool hungary(int v){ visx[v] = true; for(int i = 1; i <= ny; i++) { if(visy[i]) continue; if(lx[v] + ly[i] == s[v][i]) { visy[i] = true; if(match[i] == -1 || hungary(match[i])) { match[i] = v; return true; } } else slack[i] = min(slack[i], lx[v] + ly[i] - s[v][i]); } return false;}void km(){ memset(match, -1, sizeof match); memset(ly, 0, sizeof ly); memset(lx, 0, sizeof lx); for(int i = 1; i <= nx; i++) for(int j = 1; j <= ny; j++) lx[i] = max(lx[i], s[i][j]); for(int i = 1; i <= nx; i++) { memset(slack, 0x3f, sizeof slack); while(true) { memset(visx, 0, sizeof visx); memset(visy, 0, sizeof visy); if(hungary(i)) break; else { int d = INF; for(int j = 1; j <= ny; j++) if(!visy[j]) d = min(d, slack[j]); 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; else slack[j] -= d; } } }}int main(){ int n, m; while(~ scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { scanf("%d", &s[i][j]); s[i][j] *= 100; } int tm, tmp = 0; for(int i = 1; i <= n; i++) { scanf("%d", &tm); tmp += s[i][tm]; s[i][tm] += 1; } nx = n, ny = m; km(); int res = 0; for(int i = 1; i <= ny; i++) if(match[i] != -1) res += s[match[i]][i]; printf("%d %d\n", n - res % 100, res / 100 - tmp / 100); } return 0;}
0 0
- hdu 2853 Assignment KM好题
- hdu 2853 Assignment【KM+思维】好题
- HDU 2853 Assignment(KM最大匹配好题)
- HDU Assignment(KM变形好题!!!!)
- HDU 2853 Assignment KM
- HDU 2853 Assignment([好题] 求KM最大时,要求改动最少★★)
- hdu 2853 Assignment (KM小变异)
- Assignment (HDU 2853 最大权匹配KM)
- HDU 2853 Assignment (KM算法)
- hdu 2853 Assignment (KM算法)
- HDU -- 2853 Assignment 【思维 + KM算法】
- HDU 2853 Assignment(KM匹配)
- 【KM匹配】 HDOJ 2853 Assignment
- HDU_2853 Assignment KM算法
- hdu 2853 — Assignment
- HDU 3722 KM模板题
- hdu 2255 km入门题
- HDU 2255 KM模版题
- 54.多线程第一章
- android重难点解析
- C选择和冒泡排序程序心得
- 实战c++中的string系列--不要使用memset初始化string(一定别这么干)
- object-c定义属性与成员变量的区别
- hdu 2853 Assignment KM好题
- 2015校园O2O商业模式解析——从水果切入
- matlab 批处理图片
- 自己动手写cocos2dx游戏引擎(三)——Director对象
- 几何矩1
- Gradle多渠道打包
- 无法查找或打开 PDB 文件。
- unity发布程序的选项
- 关于Android自定义相机进行拍照(小米手机出现异常的原因)