Assignment(HDU2853)

Assignment

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


KM+思维;

题目大意是给你n个点去匹配m个点,然后最后一行给你一个原匹配,让你求出一个权值最大匹配,这个匹配要尽量跟那个原匹配用相同的边,也就是说求跟原匹配最少不相同的边数(在保证权值最大匹配时);

一种非常强的思维就是给每条边乘上(n+1),然后给每条老边再加上1;最后KM()求得的最大权值s/(n+1)就是最大权值,s%(n+1)就是用的老边数;

具体证明可以参考别的博客;

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
#define inf 0x3f3f3f3f 
//ios::sync_with_stdio(false);
using namespace std;
const int N=100;
const int M=200100;
const LL mod=1e9+7;
int n,m;
int ma[N][N];
int sx,sy;//二分图左部、右部的顶点数
int fx[N],fy[N];//左部、右部所匹配的顶点
int wx[N],wy[N];//左部、右部的顶标值
bool vx[N],vy[N];//左部、右部点是否加入了增广路
int mmin;//边权和顶标的最小差值 
bool find(int p){
	vx[p]=true;
	for(int i=1;i<=sy;i++){
		if(!vy[i]){
			int t=wx[p]+wy[i]-ma[p][i];
			if(t==0){
				vy[i]=true;
				if(fy[i]==-1||find(fy[i])){
					fy[i]=p;
					fx[p]=i;
					return true;
				}
			}
			else if(t>0){
				mmin=min(mmin,t);
			}
		}
	}
	return false;
}
int KM(){
	memset(fx,-1,sizeof(fx));
	memset(fy,-1,sizeof(fy));
	memset(wx,0,sizeof(wx));
	memset(wy,0,sizeof(wy));
	for(int i=1;i<=sx;i++){
		for(int j=1;j<=sy;j++){
			wx[i]=max(wx[i],ma[i][j]);//左部顶标值
		}
	}
	for(int i=1;i<=sx;i++){
		while(1){
			mmin=2e9;
			memset(vx,false,sizeof(vx));
			memset(vy,false,sizeof(vy));
			if(find(i)) break;//已经匹配正确
			for(int j=1;j<=sx;j++){
				if(vx[j]) wx[j]-=mmin;
			}
			for(int j=1;j<=sy;j++){
				if(vy[j]) wy[j]+=mmin;
			}
		}
	} 
	int sum=0;//最优匹配权值 
	for(int i=1;i<=sx;i++){
		if(fx[i]!=-1) sum+=ma[i][fx[i]];
	} 
	return sum;
}
int main(){
	ios::sync_with_stdio(false);
	while(cin>>n>>m){
		sx=n,sy=m;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>ma[i][j];
				ma[i][j]*=(n+1);
			}
		}
		int sum=0;//原先权值 
		for(int i=1;i<=n;i++){
			int q;
			cin>>q;
			sum+=ma[i][q];
			ma[i][q]++;
		}
		sum/=(n+1);
		int s=KM();
		cout<<n-s%(n+1)<<" "<<s/(n+1)-sum<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值