Description
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.
Input
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
Output
Sample Input
3 3
2 1 3
3 2 4
1 26 2
2 1 3
2 3
1 2 3
1 2 3
1 2
Sample Output
2 26
1 2
最近在水KM算法 只要把KM理解了 至今寫到的大部分都是水題
唯獨這題讓我寫了很長時間 看了其他人的博客才明白什麼叫建圖的巧妙和重要性
題意 有n家公司和m個任務 所有任務和公司都已經匹配好了 要求在儘量保留原有匹配的基礎上 求得最優匹配 輸出改變的數量 和 改變後增加的權值
巧妙的思路來了 首先對於所有輸入的權值增大K倍 這裏的K必須大於n 再對原匹配的權值都加 1 這樣 原匹配的優先級將大於其他匹配
再套模板 這時出來的結果 將是匹配權值數的K倍再加上原匹配的數目 (所以這裏就體現了K大於n的原因了 若是K小於n 那麼大於K的部分將可能成爲原匹配數目,結果將亂套………………
ac code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;
const int maxn=55;
const int inf=0x3f3f3f3f;
int cnum,mnum;
int linky[maxn],lx[maxn],ly[maxn];
bool visx[maxn],visy[maxn];
int g[maxn][maxn],slack[maxn];
bool dfs(int x)
{
visx[x]=true;
for(int y=1;y<=mnum;y++)
{
if(visy[y]) continue;
int t=lx[x]+ly[y]-g[x][y];
if(t==0)
{
visy[y]=true;
if(linky[y]==-1||dfs(linky[y]))
{
linky[y]=x;
return true;
}
}
else if(slack[y]>t) slack[y]=t;
}
return false;
}
int KM()
{
memset(linky,-1,sizeof linky);
memset(ly,0,sizeof ly);
for(int i=1;i<=cnum;i++)
{
lx[i]=-inf;
for(int j=1;j<=mnum;j++)
if(g[i][j]>lx[i]) lx[i]=g[i][j];
}
for(int x=1;x<=cnum;x++)
{
for(int i=1;i<=mnum;i++) slack[i]=inf;
while(true)
{
memset(visx,false,sizeof visx);
memset(visy,false,sizeof visy);
if(dfs(x)) break;
int d=inf;
for(int i=1;i<=mnum;i++)
if(!visy[i]&&d>slack[i]) d=slack[i];
for(int i=1;i<=cnum;i++)
if(visx[i]) lx[i]-=d;
for(int i=1;i<=mnum;i++)
if(visy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
int result=0;
for(int i=1;i<=mnum;i++)
{
if(linky[i]>-1)
result+=g[linky[i]][i];
}
return result;
}
int main()
{
int eff;
while(scanf("%d%d",&cnum,&mnum)!=EOF)
{
int prenum=0,m;
for(int i=1;i<=cnum;i++)
for(int j=1;j<=mnum;j++)
{
scanf("%d",&eff);
g[i][j]=eff*100;
}
for(int i=1;i<=cnum;i++)
{
scanf("%d",&m);
prenum+=g[i][m];
g[i][m]++;
}
int ans=KM();
printf("%d %d\n",cnum-ans%100,ans/100-prenum/100);
}
return 0;
}
這個技巧必須有阿!!!!!!!