Assignment
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1276 Accepted Submission(s): 667
Problem Description
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.
Input
For each test case, the first line contains two numbers N and M. N lines follow. Each contains M integers, representing Eij. The next line contains N integers. The first one represents the mission number that company 1 takes, and so on.
1<=N<=M<=50, 1<Eij<=10000.
Your program should process to the end of file.
Output
For each the case print two integers X and Y. X represents the number of companies whose mission had been changed. Y represents the maximum total efficiency can be increased after changing.
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
Source
2009 Multi-University Training Contest 5 - Host by NUDT
题目大意:
给你一个n*m的矩阵,保证n<=m,然后给你一个原匹配,让你求一个最优匹配,使得这个最优匹配的匹配上的人和给出的原匹配尽量的相似,让你求出不相似的人的个数,以及最优匹配和原匹配的差值。
分析样例:
对应第一组:
2 1 3
3 2 4
1 26 2
显然有两种匹配方式能够达到最优匹配(32):①第一行第三个,第二行第一个,第三行第二个。不相似的个数:2
②第一行第一个,第二行第三个,第三杭第二个。不相似的个数:3
那么尽量更小的一样,那么输出2 32-原匹配(6) 2 26;
思路:
1、思路来源自网络,脑洞题,菜鸡做不出 。
2、首先分析这样一个问题:在最优匹配问题上,想要得到一个最优匹配,很明显需要一个突出的权值才能使得我们将其匹配上,那么我们考虑的重点就应该放在修改原矩阵权值上来。那么如果我们想要修改权值,并且还想在修改权值之后在某种程度上得到的最优匹配和原矩阵的最优匹配值相同,那么我们设定一个值k,令原矩阵的所有值都乘以k,得到的最优匹配值ans/k==原矩阵的最优匹配。
3、那么我们又要如何保证尽量匹配的结果和原匹配相似呢?其实这个时候我们可以在原匹配的那些位子上的权值都加一,使得这些值被匹配上更加有优势(相对于同权值匹配更加有优势,但是一定不会影响更优匹配)。那么我们在这些位子上权值都加了一,那么最终匹配的权值和如何保证/k之后和原矩阵的最优匹配值相同呢?这就要保证k大于n才行。这样,我们既能在同等权值匹配的条件下尽量选择我们的原匹配,还能保证了得到的权值和/k与原矩阵的匹配值相同。
4、那么相似的匹配个数其实就是ans%k;那么其不相似的个数:n-ans%k;最优匹配的值和原匹配的值相差:ans/k-原匹配的值,为了问题简化,我们设定k为100即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[500][500];
int nn,mm,k;
int tmp[500];
int lx[500];
int ly[500];
int vx[500];
int vy[500];
int match[500];
int low;
int find(int u)
{
vx[u]=1;
for(int i=1;i<=mm;i++)
{
if(vy[i]==1)continue;
int tmp=lx[u]+ly[i]-a[u][i];
if(tmp==0)
{
vy[i]=1;
if(match[i]==-1||find(match[i]))
{
match[i]=u;
return 1;
}
}
else if(tmp<low)low=tmp;
}
return 0;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(lx,0,sizeof(lx));
memset(ly,0,sizeof(ly));
for(int i=1;i<=nn;i++)
{
for(int j=1;j<=mm;j++)
{
lx[i]=max(lx[i],a[i][j]);
}
}
for(int i=1;i<=nn;i++)
{
while(1)
{
low=0x3f3f3f3f;
memset(vx,0,sizeof(vx));
memset(vy,0,sizeof(vy));
if(find(i))break;
for(int j=1;j<=nn;j++)
{
if(vx[j])lx[j]-=low;
}
for(int j=1;j<=mm;j++)
{
if(vy[j])ly[j]+=low;
}
}
}
int sum=0;
for(int i=1;i<=mm;i++)
{
if(match[i]==-1)continue;
sum+=a[match[i]][i];
}
printf("%d ",nn-sum%100);
return sum;
}
int main()
{
while(~scanf("%d%d",&nn,&mm))
{
for(int i=1;i<=nn;i++)
{
for(int j=1;j<=mm;j++)
{
scanf("%d",&a[i][j]);
a[i][j]*=100;
}
}
int sum2=0;
for(int i=1;i<=nn;i++)
{
scanf("%d",&tmp[i]);
sum2+=a[i][tmp[i]]/100;
a[i][tmp[i]]++;
}
int sum=KM();
printf("%d\n",sum/100-sum2);
}
}