宣传
题解
0.一些想说的话
布置的作业里有这道题,做完后发现题解好少……而且很多都是用了KM最佳匹配等我这种蒟蒻看不懂的算法,于是我就来写了这篇题解。如有雷同,纯属巧合。
1.思路
做这道题的大家应该已经发现了:(1leq nleq 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;
}
本题解已同步至洛谷博客