1559 运动员最佳匹配问题

本文介绍了一道算法题目——1559 运动员最佳匹配问题,涉及男女双打比赛,目标是最大化双方优势总和。通过二分图算法,结合搜索与剪枝策略来优化解决方案,以避免超时错误。文章讨论了如何利用搜索加剪枝的方法,以及剪枝在搜索过程中的应用,以提高算法效率。

1559 运动员最佳匹配问题

看到题面这么短,我好开心啊
给定两个数组,p[i][j]是男女双打,男优势;Q[i][j]是男女双打,女优势;两个人的优势便是p[i][j]*Q[i][j],设计一个算法,使得两个优势总和最大
很明显是一个二分图算法,搜索的原因便是搜索二分图
当然这个题乱七八糟的做法什么都有KM算法,最大流,不过我还是用搜索加剪枝吧
搜索每一个男运动员,为他去搜索匹配每一个没有用过的女运动员,最后算出每种匹配的竞赛优势
最后在所有方案中选最大的
不过,这种做法会超时,TLE两个点

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,p[25][25],q[25][25],s,ans;
bool v[25]; //需要确定每个女运动员是否已匹配。
void dfs(int x)
{
	if(x>n)//搜索结束,记录答案 
	{
		ans=max(s,ans);
		return;
	}
	for(int i=1;i<=n;i++)//接着搜 
	{
		if(!v[i])//未访问 
		{
			v[i]=1;
			s += p[x][i]*q[i][x];//计算方案 
			dfs(x + 1);//接着往下搜索 
			s-=p[x][i]*q[i][x];//回溯 
			v[i]=0;
		}
	}
		
}
int main()
{
	cin >> n;
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
				scanf("%d",&p[i][j]);//输入p数组 
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
				scanf("%d",&q[i][j]);//输入q数组 
	dfs(1);//从第一个开始搜索 
	cout<<ans;
	return 0;
}

众所周知,80分
我们也可以用剪枝来解决这个问题,看可以剪掉已经不可能的情况,在任何一种搜索的情况的竞赛优势理论+原来已搜索部分仍然没有之前搜的答案大,说明这条路不可能搜了,直接结束
不一定可以配出此情况,但是理论最大值肯定比实际最大值要大,所以如果理论最大值都没有已搜过的完整路的答案大,实际上按这条路搜下去必定无法更新答案
所以,就没必要浪费时间
这个算法好像是A*搜索当中的思想

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,p[25][25],q[25][25],maxx[25],s,ans;
bool v[25];
void dfs(int x)//搜索层数 
{
	int sum = s;
	for(int i = x;i <= n;i++)//从当前层数往后搜索 
	{
	    int maxx = 0;//理论最大值 
	    for(int j=1;j<=n;j++)
	    	maxx=max(maxx,p[i][j]*q[j][i]);//比较最大的匹配优势 
	    sum += maxx;//然后计算理论最大值   
	}
	if(sum<=ans) return;//如果当前的理论比不上答案,剪枝 
	if(x>n)//达到层数 
	{
		ans=max(s,ans);//记录答案 
		return;
	}
	for(int i=1;i<=n;i++)
		if (!v[i])//未被访问的点 
		{
			v[i]=1;
			s+=p[x][i]*q[i][x];//计算答案 
			dfs(x+1);//下一层 
			s-=p[x][i]*q[i][x];//回溯 
			v[i]=0;
		}
}
int main()
{
	cin >> n;
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
			scanf("%d",&p[i][j]);
	for (int i = 1;i <= n;i++)
		for (int j = 1;j <= n;j++)
			scanf("%d",&q[i][j]);

	dfs(1);
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值