题意
长度为\(n\)的环上,Alice要从\(s_1\)出发前往\(e_1\),Bob要从\(s_2\)出发前往\(e_2\)。路径花费为经过的边权之和,且双方路径的公共部分边权会三倍计算。那么Alice和Bob分别有两种选择,对应2*2=4 种结果。在双方都想最小化自身花费的前提下,求解Alice和Bob的混合策略纳什均衡。
思路
大部分xcpc选手不具备纳什均衡的预备知识,更不知道什么是混合策略纳什均衡。好在题目的Note部分提供了相关讲解。
所以赛中解题的关键在于快速理解并接受这部分知识,搞懂题目究竟要我们求什么。搞懂之后并不难做。
但是在场中完成这件事并不容易。混合策略的纳什均衡在两方面略反直觉(或者说让人不习惯):
- 在决策中引入概率,并以期望的形式表示决策结果
- 决策双方既非合作关系,也非对立关系
此外,在开题决策上,因为存在“看了不一定懂,懂了不一定会做,做了不一定过”的风险,也会让大部分队伍选择不开这道题。
队友表示学过纳什均衡,就让他去开这题。另外两人没有相关知识背景,也帮不上忙。
当时的局面就是,这题过了就稳出线。
最后没过。据说卡在了纯策略的case,即求解出AB中某一方的概率策略分布不在\([0,1]\)区间时的处理。
好在最后还是出线了233。
代码
代码不长,计算实际花费的时候写了个暴力。
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const int N=55;
int d[N],n,s[2],e[2],a[2][2],b[2][2];
bool vis[N];
void calc(int x,int y){
for(int i=1;i<=n;++i)vis[i]=false;
a[x][y]=b[x][y]=0;
int s0=s[0],e0=e[0];
if(x)swap(s0,e0);
for(int i=s0;i!=e0;i=i%n+1){
vis[i]=true;
a[x][y]+=d[i];
}
int s1=s[1],e1=e[1];
if(y)swap(s1,e1);
for(int i=s1;i!=e1;i=i%n+1){
b[x][y]+=d[i];
if(vis[i]){
b[x][y]+=d[i]+d[i];
a[x][y]+=d[i]+d[i];
}
}
}
int main(){
int T;
scanf("%d",&T);
while(T--) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)scanf("%d", d + i);
for (int i = 0; i < 2; ++i)scanf("%d%d", s + i, e + i);
for (int x = 0; x < 2; ++x)for (int y = 0; y < 2; ++y)calc(x, y);
int b0=a[1][1]-a[0][1],k0=b0+a[0][0]-a[1][0];
int b1=b[1][1]-b[1][0],k1=b1+b[0][0]-b[0][1];
db q=1.0*b0/k0,p=1.0*b1/k1;
if(q<0||q>1){
if(-b0>0){
p=0;
q=-b1>0?0:1;
}else{
p=1;
q=k1-b1>0?0:1;
}
}
if(p<0||p>1){
if(-b1>0){
q=0;
p=-b0>0?0:1;
}else{
q=1;
p=k0-b0>0?0:1;
}
}
db ans0=p*q*a[0][0]+(1-p)*q*a[1][0]+p*(1-q)*a[0][1]+(1-p)*(1-q)*a[1][1];
db ans1=p*q*b[0][0]+(1-p)*q*b[1][0]+p*(1-q)*b[0][1]+(1-p)*(1-q)*b[1][1];
printf("%.12f %.12f\n",ans0,ans1);
}
return 0;
}
总结
这题考察临场快速学习并掌握陌生知识的能力,很有代表性。
平时多看点书还是有用。啥书都行。