hdu 2853 Assignment KM算法

题目链接: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=55;
 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]=1;
 19     for (int y=1 ;y<=m ;y++)
 20     {
 21         if (visy[y]) continue;
 22         int t=lx[x]+ly[y]-w[x][y];
 23         if (t==0)
 24         {
 25             visy[y]=1;
 26             if (link[y]==-1 || dfs(link[y]))
 27             {
 28                 link[y]=x;
 29                 return 1;
 30             }
 31         }
 32         else if (slack[y]>t) slack[y]=t;
 33     }
 34     return 0;
 35 }
 36
 37 void KM()
 38 {
 39     memset(link,-1,sizeof(link));
 40     memset(ly,0,sizeof(ly));
 41     for (int i=1 ;i<=n ;i++)
 42     {
 43         lx[i]=-inf;
 44         for (int j=1 ;j<=m ;j++)
 45             lx[i]=max(lx[i],w[i][j]);
 46     }
 47     for (int x=1 ;x<=n ;x++)
 48     {
 49         for (int i=1 ;i<=m ;i++) slack[i]=inf;
 50         while (1)
 51         {
 52             memset(visx,0,sizeof(visx));
 53             memset(visy,0,sizeof(visy));
 54             if (dfs(x)) break;
 55             int d=inf;
 56             for (int i=1 ;i<=m ;i++)
 57             {
 58                 if (!visy[i] && slack[i]<d) d=slack[i];
 59             }
 60             for (int i=1 ;i<=n ;i++)
 61                 if (visx[i]) lx[i] -= d;
 62             for (int i=1 ;i<=m ;i++)
 63             {
 64                 if (visy[i]) ly[i] += d;
 65                 else slack[i] -= d;
 66             }
 67         }
 68     }
 69     int ans=0,cnt=0;
 70     for (int i=1 ;i<=m ;i++)
 71     {
 72         if (link[i]!=-1)
 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,0,sizeof(w));
 91         memset(vis,0,sizeof(vis));
 92         k=200;
 93         for (int i=1 ;i<=n ;i++)
 94         {
 95             for (int j=1 ;j<=m ;j++)
 96             {
 97                 scanf("%d",&w[i][j]);
 98                /// w[i][j] *= k;
 99             }
100         }
101         int a;
102         sum=0;
103         for (int i=1 ;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]=1;
110         }
111         KM();
112     }
113     return 0;
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=55;
 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]=1;
 18     for (int y=1 ;y<=m ;y++)
 19     {
 20         if (visy[y]) continue;
 21         int t=lx[x]+ly[y]-w[x][y];
 22         if (t==0)
 23         {
 24             visy[y]=1;
 25             if (link[y]==-1 || dfs(link[y]))
 26             {
 27                 link[y]=x;
 28                 return 1;
 29             }
 30         }
 31         else if (slack[y]>t) slack[y]=t;
 32     }
 33     return 0;
 34 }
 35
 36 void KM()
 37 {
 38     memset(link,-1,sizeof(link));
 39     memset(ly,0,sizeof(ly));
 40     for (int i=1 ;i<=n ;i++)
 41     {
 42         lx[i]=-inf;
 43         for (int j=1 ;j<=m ;j++)
 44             lx[i]=max(lx[i],w[i][j]);
 45     }
 46     for (int x=1 ;x<=n ;x++)
 47     {
 48         for (int i=1 ;i<=m ;i++) slack[i]=inf;
 49         while (1)
 50         {
 51             memset(visx,0,sizeof(visx));
 52             memset(visy,0,sizeof(visy));
 53             if (dfs(x)) break;
 54             int d=inf;
 55             for (int i=1 ;i<=m ;i++)
 56             {
 57                 if (!visy[i] && slack[i]<d) d=slack[i];
 58             }
 59             for (int i=1 ;i<=n ;i++)
 60                 if (visx[i]) lx[i] -= d;
 61             for (int i=1 ;i<=m ;i++)
 62             {
 63                 if (visy[i]) ly[i] += d;
 64                 else slack[i] -= d;
 65             }
 66         }
 67     }
 68     int ans=0,cnt=0;
 69     for (int i=1 ;i<=m ;i++)
 70     {
 71         if (link[i]!=-1) 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,0,sizeof(w));
 81         k=200;
 82         for (int i=1 ;i<=n ;i++)
 83         {
 84             for (int j=1 ;j<=m ;j++)
 85             {
 86                 scanf("%d",&w[i][j]);
 87                 w[i][j] *= k;
 88             }
 89         }
 90         int a;
 91         sum=0;
 92         for (int i=1 ;i<=n ;i++)
 93         {
 94             scanf("%d",&a);
 95             sum += w[i][a]/k;
 96             w[i][a] ++ ;
 97         }
 98         KM();
 99     }
100     return 0;
101 }
时间: 2024-08-28 11:13:48

hdu 2853 Assignment KM算法的相关文章

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

HDU 2853 Assignment 题目链接 题意:现在有N个部队和M个任务(M>=N),每个部队完成每个任务有一点的效率,效率越高越好.但是部队已经安排了一定的计划,这时需要我们尽量用最小的变动,使得所有部队效率之和最大.求最小变动的数目和变动后和变动前效率之差. 思路:对于如何保证改变最小,没思路,看了别人题解,恍然大悟,表示想法非常机智 试想,如果能让原来那些匹配边,比其他匹配出来总和相同的权值还大,对结果又不影响,那就简单了,这个看似不能做到,其实是可以做到的 数字最多选出50个,所

hdu 2853 Assignment 费用流

就是本来就给出了一个匹配,然后让你求一个权值最大的匹配,并且和初始匹配变动最小. #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=400; const int MAXE=20000000; const int inf=1<<30; int head[N],s,t,cnt,ans; int d[N],pre[N]; bool

【二分图匹配入门专题1】L - Card Game hdu 3722【km算法】

Jimmy invents an interesting card game. There are N cards, each of which contains a string Si. Jimmy wants to stick them into several circles, and each card belongs to one circle exactly. When sticking two cards, Jimmy will get a score. The score of

HDU 2853 最大匹配&amp;KM模板

http://acm.hdu.edu.cn/showproblem.php?pid=2853 这道题初看了没有思路,一直想的用网络流如何解决 参考了潘大神牌题解才懂的 最大匹配问题KM 还需要一些技巧来解决最小变动, 做法是:把原先的邻接矩阵每个数扩大k倍(k>n) 为了突出原先的选择,也就是同等情况下优先选择原来的方案 给原来的方案对应矩阵内的数据+1 那么 最终得出的最大匹配值/k=真实的最大匹配 最终得出的最大匹配值%k=原来的方案采用了几个 这里的KM留下来做模板 /* 二分图最佳匹配

Assignment (HDU 2853 最大权匹配KM)

Assignment Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1068    Accepted Submission(s): 551 Problem Description Last year a terrible earthquake attacked Sichuan province. About 300,000 PLA s

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 accommodation plan with every student assigned to a suitable apartment while keeping everyone happy, let alone an optimal one. Recently the president of

hdu 2426 Interesting Housing Problem (KM算法)

Interesting Housing Problem Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2388    Accepted Submission(s): 879 Problem Description For any school, it is hard to find a feasible accommodation

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

HDU 2255 奔小康赚大钱(二分匹配之KM算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子. 另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓