Painters’ Duel
题目链接
题目简介
在一个 S S S等分三角图中, A 和 B A和B A和B两个人分别有一个起始位置,在图中有些位置不可经过且所有位置不可重复经过(假如 A A A走过了(2,2),那么A和B均不能再经过(2,2)),两个人都试图使自己所经过的位置数量最大化,假设 A 和 B A和B A和B两个人所做的选择均为最优选择,求在 A 和 B A和B A和B不能移动时, A A A所经过的位置数减去 B B B所经过的位置数。
下图为S=3时的情况
解题思路
这道题我看在比赛中通过的人数很少,其实如果思路想清楚了,还是比较简单的。
- 乍一看是博弈感觉很难,其实不要被吓到
- 肯定是要用深度优先搜索的
- 由于 A A A是要最大化结果,而 B B B是要最小化结果,所以在深度搜索时要分情况
- 在自顶向下的深度搜索过程中,其实我们是不知道每一步的移动是否为最优策略,我们只是简单的遍历
- 但是在自底向上的回溯过程中,我们是可以比较每一步移动对结果的影响,这样只需要选择出每一步最优策略就好了(即对于 A A A来说最大化结果,对于 B B B来说最小化结果)
代码
talk is cheap , show me the code
其实我发现很多题解对于解题思路的描述都是轻描淡写的,寥寥数笔就直接放代码了,我也是极度不情愿看代码的,因为每个人都有自己的风格,但是我还是想说看代码(前提是正确的)也是一种能力,大部分思想可以通过代码来体现
#include<bits/stdc++.h>
using namespace std;
int T,S,RA,PA,RB,PB,C;
bool vis[7][12];
pair<int,int> dfs(int xa,int ya,int xb,int yb,bool flag,bool ifstopa,bool ifstopb){
if(ifstopa&&ifstopb)return{0,0};
else if((ifstopa&&flag)||(ifstopb&&!flag))return dfs(xa,ya,xb,yb,flag^1,ifstopa,ifstopb);
else{
int x,y,x_n,y_n;
pair<int,int>ans={0,0};
pair<int,int>ans_each;
bool flag_update=0;
bool ifmove=0;
if(flag){
x = xa;
y = ya;
}else{
x = xb;
y = yb;
}
for(int i=0;i<3;i++){
if(i==0){
x_n = x;
y_n = y-1;
}else if(i==1){
x_n = x;
y_n = y+1;
}else if(i==2){
if(y%2==1){
x_n = x+1;
y_n = y+1;
}else{
x_n = x-1;
y_n = y-1;
}
}
if(y_n>2*x_n-1||x_n==0||y_n==0||x_n>S||vis[x_n][y_n])continue;
vis[x_n][y_n] = 1;
ifmove = 1;
if(flag)ans_each = dfs(x_n,y_n,xb,yb,flag^1,ifstopa,ifstopb);
else ans_each = dfs(xa,ya,x_n,y_n,flag^1,ifstopa,ifstopb);
if(!flag_update){
ans = ans_each;
flag_update = 1;
}else if(flag&&ans.first-ans.second<ans_each.first-ans_each.second){
ans = ans_each;
}else if(!flag&&ans.first-ans.second>ans_each.first-ans_each.second){
ans = ans_each;
}
vis[x_n][y_n] = 0;
}
if(flag&&!ifmove){ifstopa=1;ans=dfs(xa,ya,xb,yb,flag^1,ifstopa,ifstopb);}
else if(!flag&&!ifmove){ifstopb=1;ans=dfs(xa,ya,xb,yb,flag^1,ifstopa,ifstopb);}
if(ifmove&&flag)return {ans.first+1,ans.second};
else if(ifmove&&!flag)return {ans.first,ans.second+1};
else return ans;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int num1,num2;
cin >> T;
for(int g=1;g<=T;g++){
memset(vis,0,sizeof(vis));
cin >> S >> RA >> PA >> RB >> PB >> C;
vis[RA][PA] = 1;
vis[RB][PB] = 1;
for(int i=1;i<=C;i++){
cin >> num1 >> num2;
vis[num1][num2] = 1;
}
pair<int,int>ans = dfs(RA,PA,RB,PB,1,0,0);
cout << "Case #" << g << ": " << ans.first-ans.second << "\n";
}
}