Assignment
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 566 Accepted Submission(s): 290
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.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
/*
因爲我們要變動最小,所以對在原計劃中的邊要有一些特殊照顧,
使得最優匹配時,儘量優先使用原計劃的邊,這樣變化才能是最小的且不會影響原匹配。
根據這個思想,我們可以把每條邊的權值擴大k倍,k要大於n。
然後對原計劃的邊都+1。精華全在這裏。我們來詳細說明一下。
全部邊都擴大了k倍,而且k比n大,這樣,我們求出的最優匹配就是k倍的最大權值,
只要除以k就可以得到最大權值。實現原計劃的邊加1,這樣,在每次選擇邊時,
這些變就有了優勢,就會優先選擇這些邊。假如原計劃的h條邊被選入了最優匹配中,這樣,
最優權值就是k倍的最大權值+k(原計劃的每條邊都+1)。但是k大於n的用意何在呢?
我們發現假如原計劃的邊全部在匹配中,只會增加n,又n<k,
所以除以k後不會影響最優匹配的最大權值之和,
然後我們對k取餘,就正好得到加入的原計劃的邊的個數。
這時,我們只需要用總點數-加入的原計劃的點數,就可以求得最小變動數了。
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 99999999
#define maxn 305
int lx[maxn],ly[maxn];//頂標
int Match[maxn];//記錄匹配值
int visx[maxn],visy[maxn];
int w[maxn][maxn];//權值
int slack[maxn];//slack爲修改量
int ans,n,m;
bool findPath(int x)//尋找最優解
{
int temp;
visx[x]=1;
for(int y=1; y<=m; y++)
{
if(visy[y])continue;
if(w[x][y]==lx[x]+ly[y])//說明是相等子圖
{
visy[y]=1;
if(!Match[y]||findPath(Match[y]))
{
Match[y]=x;
return true;
}
}
else
slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]);
}
return false;
}
void km()
{
memset(Match,0,sizeof(Match));
//初始化頂標
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
lx[i]=max(lx[i],w[i][j]);//
for(int x=1; x<=n; x++)
{
for(int i=1;i<=m;i++)
slack[i]=INF;
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(findPath(x))break;
int tmp=INF;
for(int i=1;i<=m;i++)
{
if(!visy[i])
{
if(tmp>slack[i])
tmp=slack[i];
}
}
if(tmp==INF)return ;
for(int i=1; i<=m; i++)
{
if(visx[i]) lx[i]-=tmp;
if(visy[i]) ly[i]+=tmp;
else
slack[i]-=tmp;
}
}
}
}
int main()
{
int tt,sum;
while(scanf("%d %d",&n,&m)!=EOF)
{
ans=0;
sum=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
scanf("%d",&w[i][j]);
w[i][j]*=100;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&tt);
w[i][tt]++;
sum+=w[i][tt];
}
km();
for(int i=1; i<=m; i++)
ans+=w[Match[i]][i];
printf("%d %d\n",sum%100-ans%100,ans/100-sum/100);
}
return 0;
}