[洛谷P1559][题解]运动员最佳匹配问题

宣传

我的博客园

题解

题目戳我

0.一些想说的话

布置的作业里有这道题,做完后发现题解好少……而且很多都是用了KM最佳匹配等我这种蒟蒻看不懂的算法,于是我就来写了这篇题解。如有雷同,纯属巧合。

1.思路

做这道题的大家应该已经发现了:\(1\leq n\leq 20\)
这种数据范围,不是状压就是爆搜。这里我们选择搜索解决本题(还不是因为状压不熟练

2.实现

既然是搜索,那么肯定有一个顺序。我选择的是枚举男的,搜女的。

3.剪枝&&细节

爆搜肯定是过不去的,我们考虑剪枝。
这道题可以采用一种类似A*的剪枝方式,令\(h[i]\)为第\(i\)个男运动员能匹配到的最大竞赛优势,在搜索函数内枚举,如果所有最大的加起来都不够之前得到的\(ans\),那么就可以直接跳出了。

代码

前面的缺省源因为太长省略了,具体可以去我的博客里找

#define N 30
int n,ans,p[N][N],q[N][N],h[N],vis[N];
//p,q:如题意所示 
//h:题解里提到的估价数组 
//vis:搜索用的 
void DFS(int now,int sum){
	//now:当前枚举到的男运动员 
	//sum:当前的总竞赛优势 
	if(now>n){//枚举完了 
		ans=max(ans,sum);
		return;
	}
	int hstar=0;
	for(rg int i=now;i<=n;i++){
		hstar+=h[i];
	}
	//如果之后的都取最大也达不到就返回 
	if(sum+hstar<ans)return;
	for(rg int i=1;i<=n;i++){
		if(!vis[i]){
			vis[i]=1;
			//枚举下一个,一定要注意顺序! 
			DFS(now+1,sum+p[now][i]*q[i][now]);
			vis[i]=0;
		}
	}
}
int main(){
	//读入部分 
	Read(n);
	for(rg int i=1;i<=n;i++){
		for(rg int j=1;j<=n;j++){
			Read(p[i][j]);
		}
	}
	for(rg int i=1;i<=n;i++){
		for(rg int j=1;j<=n;j++){
			Read(q[i][j]);
		}
	}
	//提前算出h数组,计算方式如题解所说 
	for(rg int i=1;i<=n;i++){
		for(rg int j=1;j<=n;j++){
			h[i]=max(h[i],p[i][j]*q[j][i]);
		}
	}
	DFS(1,0);
	cout<<ans<<endl;//圆满结束 
	return 0;
}

本题解已同步至洛谷博客

posted @ 2020-04-10 14:28  ajthreac  阅读(283)  评论(0编辑  收藏  举报