题目链接: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,和直接求得的最大效率不是一样的吗?
若有大牛明白其中奥妙,还望指点一二,在此感谢。
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
const int maxn=; int n,m,k,sum;
int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
int link[maxn],slack[maxn],w[maxn][maxn];
int vis[maxn][maxn]; int dfs(int x)
{
visx[x]=;
for (int y= ;y<=m ;y++)
{
if (visy[y]) continue;
int t=lx[x]+ly[y]-w[x][y];
if (t==)
{
visy[y]=;
if (link[y]==- || dfs(link[y]))
{
link[y]=x;
return ;
}
}
else if (slack[y]>t) slack[y]=t;
}
return ;
} void KM()
{
memset(link,-,sizeof(link));
memset(ly,,sizeof(ly));
for (int i= ;i<=n ;i++)
{
lx[i]=-inf;
for (int j= ;j<=m ;j++)
lx[i]=max(lx[i],w[i][j]);
}
for (int x= ;x<=n ;x++)
{
for (int i= ;i<=m ;i++) slack[i]=inf;
while ()
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if (dfs(x)) break;
int d=inf;
for (int i= ;i<=m ;i++)
{
if (!visy[i] && slack[i]<d) d=slack[i];
}
for (int i= ;i<=n ;i++)
if (visx[i]) lx[i] -= d;
for (int i= ;i<=m ;i++)
{
if (visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int ans=,cnt=;
for (int i= ;i<=m ;i++)
{
if (link[i]!=-)
{
ans += w[link[i] ][i];
if (vis[link[i] ][i]) cnt++;
}
}
printf("%d %d\n",n-cnt,ans-sum-cnt);
// for (int i=1 ;i<=m ;i++)
// {
// if (link[i]!=-1) ans += w[link[i] ][i];
// }
// printf("%d %d\n",n-ans%k,ans/k-sum);
} int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(w,,sizeof(w));
memset(vis,,sizeof(vis));
k=;
for (int i= ;i<=n ;i++)
{
for (int j= ;j<=m ;j++)
{
scanf("%d",&w[i][j]);
/// w[i][j] *= k;
}
}
int a;
sum=;
for (int i= ;i<=n ;i++)
{
scanf("%d",&a);
sum += w[i][a];
///sum += w[i][a]/k;
w[i][a] ++ ;
vis[i][a]=;
}
KM();
}
return ;
}

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

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

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
const int maxn=; int n,m,k,sum;
int lx[maxn],ly[maxn],visx[maxn],visy[maxn];
int link[maxn],slack[maxn],w[maxn][maxn]; int dfs(int x)
{
visx[x]=;
for (int y= ;y<=m ;y++)
{
if (visy[y]) continue;
int t=lx[x]+ly[y]-w[x][y];
if (t==)
{
visy[y]=;
if (link[y]==- || dfs(link[y]))
{
link[y]=x;
return ;
}
}
else if (slack[y]>t) slack[y]=t;
}
return ;
} void KM()
{
memset(link,-,sizeof(link));
memset(ly,,sizeof(ly));
for (int i= ;i<=n ;i++)
{
lx[i]=-inf;
for (int j= ;j<=m ;j++)
lx[i]=max(lx[i],w[i][j]);
}
for (int x= ;x<=n ;x++)
{
for (int i= ;i<=m ;i++) slack[i]=inf;
while ()
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if (dfs(x)) break;
int d=inf;
for (int i= ;i<=m ;i++)
{
if (!visy[i] && slack[i]<d) d=slack[i];
}
for (int i= ;i<=n ;i++)
if (visx[i]) lx[i] -= d;
for (int i= ;i<=m ;i++)
{
if (visy[i]) ly[i] += d;
else slack[i] -= d;
}
}
}
int ans=,cnt=;
for (int i= ;i<=m ;i++)
{
if (link[i]!=-) ans += w[link[i] ][i];
}
printf("%d %d\n",n-ans%k,ans/k-sum);
} int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(w,,sizeof(w));
k=;
for (int i= ;i<=n ;i++)
{
for (int j= ;j<=m ;j++)
{
scanf("%d",&w[i][j]);
w[i][j] *= k;
}
}
int a;
sum=;
for (int i= ;i<=n ;i++)
{
scanf("%d",&a);
sum += w[i][a]/k;
w[i][a] ++ ;
}
KM();
}
return ;
}

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. WIN8 下 Hyper-V和Vmware Workstation

    1 管理员身份运行命令提示符 cmd bcdedit /copy {current} /d “Windows Without Hyper-V 2 记下 { } 中的代码 bcdedit /set {X ...

  2. API - .add()

    jQuery的 .add 很像一个collection, 官方的这个demo很形象的表达了这个意思. <!doctype html> <html lang="en" ...

  3. 信驰达携“Zigbee Light Link灯控方案”亮相第18届广州国际照明展

    2013年6月9日至12日,第18届广州国际照明展览会在琶洲中国进出口商品交易会展馆举行,作为全球照明及LED行业风向标和晴雨表,本次展会吸引了来自27个国际及地区,共2600多家企业参展.我公司受T ...

  4. 7.python字符串-内置方法分析

    上篇对python中的字符串内置方法进行了列举和简单说明,但这些方法太多,逐一背下效率实在太低,下面我来对这些方法按照其功能进行总结: 1.字母大小写相关(中文无效) 1.1 S.upper() -& ...

  5. 浅谈Objective—C中的面向对象特性

    Objective-C世界中的面向对象程序设计 面向对象称程序设计可能是现在最常用的程序设计模式.如何开发实际的程序是存在两个派系的-- 面向对象语言--在过去的几十年中,很多的面向对象语言被发明出来 ...

  6. 快速同步mysql数据到redis中

    MYSQL快速同步数据到Redis 举例场景:存储游戏玩家的任务数据,游戏服务器启动时将mysql中玩家的数据同步到redis中. 从MySQL中将数据导入到Redis的Hash结构中.当然,最直接的 ...

  7. Python 爬虫实例

    下面是我写的一个简单爬虫实例 1.定义函数读取html网页的源代码 2.从源代码通过正则表达式挑选出自己需要获取的内容 3.序列中的htm依次写到d盘 #!/usr/bin/python import ...

  8. eclipse导出Runnable Jar File在Launch Configuration中找不到类

    1.只要选择中你需要Launch Configuration中出现的类,右击Run AS -- Java Application 再次. 2.点击导出Export的时候,就可以看到类在列表中出现了. ...

  9. iOS关于打包出错

    运行没问题,有可能是自动打包编译脚本的存在,删除掉即可.

  10. scjp考试准备 - 7 - Java构造器

    题目——如下代码的执行结果: class Hello{ String title; int value; public Hello(){ title += " World!"; } ...