P4014 89分;急救!
  • 板块题目总版
  • 楼主lovely_float
  • 当前回复0
  • 已保存回复0
  • 发布时间2022/1/22 18:40
  • 上次更新2023/10/28 11:32:11
查看原帖
P4014 89分;急救!
461831
lovely_float楼主2022/1/22 18:40
#include <bits/stdc++.h>
using namespace std;

const int N=100+5,INF=1<<30;
int n;
int edge[N][N];//邻接矩阵存图(边的权值) 
int ex_left[N],ex_right[N];//左右的期望值(若要配对,左右的期望值之和应该等于权值)
bool vis_left[N],vis_right[N];//每一轮参加过匹配
int match[N];//记录右边与左边的配对 
int min_change;//若右边要跟左边配对需要多少期望值 

bool dfs(int left)
{
	vis_left[left]=true;//参加匹配
	for(int right=1;right<=n;++right){
		if(vis_right[right]||!edge[left][right]) continue;
		int gap=ex_left[left]+ex_right[right]-edge[left][right];//两边期望值相加减去权值 
		if(!gap) {
			vis_right[right]=true;//参加过了 
			if(!match[right]||dfs(match[right])){//若右边与左边没有配对或左边那位有了新的配对 
				match[right]=left;//可以配上 
				return true;
			}
		}
		else min_change=min(min_change,gap);//若右边与左边配对,要多少期盼值
	}
	return false;
}
int KM()
{
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			ex_left[i]=max(ex_left[i],edge[i][j]);//左边的期望值取与之相连的最大,右边的期望值为0
	for(int i=1;i<=n;++i)//为左边匹配右边(一轮) 
	{
		min_change=INF;
		while(true)
		{
			memset(vis_left,0,sizeof(vis_left));
			memset(vis_right,0,sizeof(vis_right));
			if(dfs(i)) break;//若找到了退出,继续下一轮
			//若没找到,左边降低期望值
			for(int j=1;j<=n;++j){
				if(vis_left[j]) ex_left[j]-=min_change;//左边参加过的降低期盼值
				if(vis_right[j]) ex_right[j]+=min_change;//右边参加过的加上最小期盼值
			}
		}
	}
	int res=0;
	for(int i=1;i<=n;++i)
		res+=edge[match[i]][i];//加上 
	return res;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",&edge[i][j]);//输入权值 
	int ans1=KM();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			edge[i][j]=-edge[i][j];
	for(int i=1;i<=n;++i)
		ex_left[i]=-INF,
		ex_right[i]=match[i]=0;
	printf("%d\n%d",-KM(),ans1);
	return 0;
}
2022/1/22 18:40
加载中...