题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853

Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA soldiers attended the rescue, also ALPCs. Our mission is to solve difficulty problems to optimization the assignment of troops. The assignment is measure by efficiency, which is an integer, and the larger the better.
We have N companies of troops and M missions, M>=N. One
company can get only one mission. One mission can be assigned to only one
company. If company i takes mission j, we can get efficiency Eij.
We have a
assignment plan already, and now we want to change some companies’ missions to
make the total efficiency larger. And also we want to change as less companies
as possible.
 
题目描述:n个组和m个任务,Eij表示第i个组完成第j个任务的效率,每个组只能完成一个任务,每个任务只能由一个组完成,目前已经有了一个计划,但是现在我们想要让总效率达到最大,并且在此前提下还需要改变重新分配任务的组的个数最少。求出最大效率减去原先计划的效率和重新分配任务的组的个数。
 
算法分析:这道题的思维方式的确很独特,也很巧妙。首先解决第一个问题:最大效率减去原先计划的效率的差值。最大效率很好解决,用KM算法即可,原先计划的效率直接根据输入统计即可。那么第二个问题呢?重新分配任务的组的最小个数。
方法一:首先为了保证在最大效率情况下尽量选择原先已经分配了的任务,所以我们可以对原先已经分配了的任务在效率上加1,这样即使两个组对同一个任务效率相同也会选择原先的计划,然后我们标记一下有哪些边是原先计划里的。剩下的就是KM了。
说明:这种方法为什么会WA呢,还没有找到原因, 关键在于对每条边权都要乘以一个k(k>n),下面的代码就没有乘以k,想想应该是这种方法下求得的不是最大效率吧,但为什么不是最大效率呢? 每条边都乘以k最后的最大效率再除以k,和直接求得的最大效率不是一样的吗?
若有大牛明白其中奥妙,还望指点一二,在此感谢。
  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define inf 0x7fffffff
  8. using namespace std;
  9. const int maxn=;
  10.  
  11. int n,m,k,sum;
  12. int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
  13. int link[maxn],slack[maxn],w[maxn][maxn];
  14. int vis[maxn][maxn];
  15.  
  16. int dfs(int x)
  17. {
  18. visx[x]=;
  19. for (int y= ;y<=m ;y++)
  20. {
  21. if (visy[y]) continue;
  22. int t=lx[x]+ly[y]-w[x][y];
  23. if (t==)
  24. {
  25. visy[y]=;
  26. if (link[y]==- || dfs(link[y]))
  27. {
  28. link[y]=x;
  29. return ;
  30. }
  31. }
  32. else if (slack[y]>t) slack[y]=t;
  33. }
  34. return ;
  35. }
  36.  
  37. void KM()
  38. {
  39. memset(link,-,sizeof(link));
  40. memset(ly,,sizeof(ly));
  41. for (int i= ;i<=n ;i++)
  42. {
  43. lx[i]=-inf;
  44. for (int j= ;j<=m ;j++)
  45. lx[i]=max(lx[i],w[i][j]);
  46. }
  47. for (int x= ;x<=n ;x++)
  48. {
  49. for (int i= ;i<=m ;i++) slack[i]=inf;
  50. while ()
  51. {
  52. memset(visx,,sizeof(visx));
  53. memset(visy,,sizeof(visy));
  54. if (dfs(x)) break;
  55. int d=inf;
  56. for (int i= ;i<=m ;i++)
  57. {
  58. if (!visy[i] && slack[i]<d) d=slack[i];
  59. }
  60. for (int i= ;i<=n ;i++)
  61. if (visx[i]) lx[i] -= d;
  62. for (int i= ;i<=m ;i++)
  63. {
  64. if (visy[i]) ly[i] += d;
  65. else slack[i] -= d;
  66. }
  67. }
  68. }
  69. int ans=,cnt=;
  70. for (int i= ;i<=m ;i++)
  71. {
  72. if (link[i]!=-)
  73. {
  74. ans += w[link[i] ][i];
  75. if (vis[link[i] ][i]) cnt++;
  76. }
  77. }
  78. printf("%d %d\n",n-cnt,ans-sum-cnt);
  79. // for (int i=1 ;i<=m ;i++)
  80. // {
  81. // if (link[i]!=-1) ans += w[link[i] ][i];
  82. // }
  83. // printf("%d %d\n",n-ans%k,ans/k-sum);
  84. }
  85.  
  86. int main()
  87. {
  88. while (scanf("%d%d",&n,&m)!=EOF)
  89. {
  90. memset(w,,sizeof(w));
  91. memset(vis,,sizeof(vis));
  92. k=;
  93. for (int i= ;i<=n ;i++)
  94. {
  95. for (int j= ;j<=m ;j++)
  96. {
  97. scanf("%d",&w[i][j]);
  98. /// w[i][j] *= k;
  99. }
  100. }
  101. int a;
  102. sum=;
  103. for (int i= ;i<=n ;i++)
  104. {
  105. scanf("%d",&a);
  106. sum += w[i][a];
  107. ///sum += w[i][a]/k;
  108. w[i][a] ++ ;
  109. vis[i][a]=;
  110. }
  111. KM();
  112. }
  113. return ;
  114. }

方法二:和方法一的区别就在于对每条边都乘以k(比如k=200),对于原有匹配w[x][y]++,最后的答案最大效率为ans。

那么差值=ans/k-sum;个数=n-ans%k。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define inf 0x7fffffff
  8. using namespace std;
  9. const int maxn=;
  10.  
  11. int n,m,k,sum;
  12. int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
  13. int link[maxn],slack[maxn],w[maxn][maxn];
  14.  
  15. int dfs(int x)
  16. {
  17. visx[x]=;
  18. for (int y= ;y<=m ;y++)
  19. {
  20. if (visy[y]) continue;
  21. int t=lx[x]+ly[y]-w[x][y];
  22. if (t==)
  23. {
  24. visy[y]=;
  25. if (link[y]==- || dfs(link[y]))
  26. {
  27. link[y]=x;
  28. return ;
  29. }
  30. }
  31. else if (slack[y]>t) slack[y]=t;
  32. }
  33. return ;
  34. }
  35.  
  36. void KM()
  37. {
  38. memset(link,-,sizeof(link));
  39. memset(ly,,sizeof(ly));
  40. for (int i= ;i<=n ;i++)
  41. {
  42. lx[i]=-inf;
  43. for (int j= ;j<=m ;j++)
  44. lx[i]=max(lx[i],w[i][j]);
  45. }
  46. for (int x= ;x<=n ;x++)
  47. {
  48. for (int i= ;i<=m ;i++) slack[i]=inf;
  49. while ()
  50. {
  51. memset(visx,,sizeof(visx));
  52. memset(visy,,sizeof(visy));
  53. if (dfs(x)) break;
  54. int d=inf;
  55. for (int i= ;i<=m ;i++)
  56. {
  57. if (!visy[i] && slack[i]<d) d=slack[i];
  58. }
  59. for (int i= ;i<=n ;i++)
  60. if (visx[i]) lx[i] -= d;
  61. for (int i= ;i<=m ;i++)
  62. {
  63. if (visy[i]) ly[i] += d;
  64. else slack[i] -= d;
  65. }
  66. }
  67. }
  68. int ans=,cnt=;
  69. for (int i= ;i<=m ;i++)
  70. {
  71. if (link[i]!=-) ans += w[link[i] ][i];
  72. }
  73. printf("%d %d\n",n-ans%k,ans/k-sum);
  74. }
  75.  
  76. int main()
  77. {
  78. while (scanf("%d%d",&n,&m)!=EOF)
  79. {
  80. memset(w,,sizeof(w));
  81. k=;
  82. for (int i= ;i<=n ;i++)
  83. {
  84. for (int j= ;j<=m ;j++)
  85. {
  86. scanf("%d",&w[i][j]);
  87. w[i][j] *= k;
  88. }
  89. }
  90. int a;
  91. sum=;
  92. for (int i= ;i<=n ;i++)
  93. {
  94. scanf("%d",&a);
  95. sum += w[i][a]/k;
  96. w[i][a] ++ ;
  97. }
  98. KM();
  99. }
  100. return ;
  101. }

hdu 2853 Assignment KM算法的更多相关文章

  1. 【HDU 2853】 KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853 题意:有n个公司,m个任务,每个公司做每个任务都有一个效率值,最开始每个公司都指派了一个任务,现 ...

  2. HDU 2853 Assignment(KM最大匹配好题)

    HDU 2853 Assignment 题目链接 题意:如今有N个部队和M个任务(M>=N),每一个部队完毕每一个任务有一点的效率,效率越高越好.可是部队已经安排了一定的计划,这时须要我们尽量用 ...

  3. HDU(2255),KM算法,最大权匹配

    题目链接 奔小康赚大钱 Time Limit: 1000/1000MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  4. HDU 2853 最大匹配&KM模板

    http://acm.hdu.edu.cn/showproblem.php?pid=2853 这道题初看了没有思路,一直想的用网络流如何解决 参考了潘大神牌题解才懂的 最大匹配问题KM 还需要一些技巧 ...

  5. HDU 2853 & 剩余系+KM模板

    题意: 给你一张二分图,给一个原匹配,求原匹配改动最少的边数使其边权和最大. SOL: 我觉得我的智商还是去搞搞文化课吧..这种题给我独立做我大概只能在暴力优化上下功夫.. 这题的处理方法让我想到了剩 ...

  6. 【HDU 2853】Assignment (KM)

    Assignment Problem Description Last year a terrible earthquake attacked Sichuan province. About 300, ...

  7. Assignment (HDU 2853 最大权匹配KM)

    Assignment Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. Assignment HDU - 2853(二分图匹配 KM 新边旧边)

    传送门: Assignment HDU - 2853 题意:题意直接那松神的题意了.给了你n个公司和m个任务,然后给你了每个公司处理每个任务的效率.然后他已经给你了每个公司的分配方案,让你求出最多能增 ...

  9. hdu 2426 Interesting Housing Problem 最大权匹配KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2426 For any school, it is hard to find a feasible ac ...

随机推荐

  1. C# .Net三层架构[转]

    C# .Net三层架构[转] 编写人:CC阿爸 2014-3-14 希望朋友们留下自己对三层架构的理解... 三层体系结构的概念     用户界面表示层(USL) 业务逻辑层(BLL) 数据访问层(D ...

  2. vue中的重要特性

    一.vue中的自定义组件 html的代码: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  3. RecyclerView中显示不同的item

    测试代码: activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/an ...

  4. Java 第七天 动态代理

    代理类需实现InvocationHandler接口: public interface InvocationHandler { public Object invoke(Object proxy,Me ...

  5. python内建函数-数字相关

    本篇对于数字有关的内置函数进行总结. 数字包括 int() , long() , float() , complex() ,这些函数都能够用来进行数值类型的转换.同时这些函数也接受字符串参数,返回字符 ...

  6. Linux环境下常用regexp的使用

    正则表达式 REGular EXPression   的简写元字符 匹配次数 位置锚定 分组 --------------------------------------元字符. 匹配任意单个字符 [ ...

  7. 切换两个activity

    下面是一个切换两个activity是过度动画效果实例:(注意里面的overridePendingTransition()方法)Java代码 1. @Override public void onCre ...

  8. Oracle12C的EM无法访问怎么办?

    装完Oracle 12c,想体验下EM Express,缺发现不能用,应该怎么办?12c的EM 不再像以前版本配置那么麻烦,当然提供的功能也没有那么多了,只需要启用对应端口即可,请看:To manua ...

  9. python数组的使用

    python数组的使用 2010-07-28 17:17 1.Python的数组分三种类型:(1) list 普通的链表,初始化后可以通过特定方法动态增加元素.定义方式:arr = [元素] (2) ...

  10. [转]IIS部署托管管道模式的集成和经典区别

    关于ESPS和SCSJ在Windows server 2008的问题总结 SCSJ出现的问题在于集成模式和经典模式的选择上,系统本身是没有问题的.我们在部署系统的时候,选择了集成模式,导致WebCon ...