kickstart 2020 F Painters‘ Duel

Painters’ Duel


题目链接


题目简介

在一个 S S S等分三角图中, A 和 B A和B AB两个人分别有一个起始位置,在图中有些位置不可经过且所有位置不可重复经过(假如 A A A走过了(2,2),那么A和B均不能再经过(2,2)),两个人都试图使自己所经过的位置数量最大化,假设 A 和 B A和B AB两个人所做的选择均为最优选择,求在 A 和 B A和B AB不能移动时, A A A所经过的位置数减去 B B B所经过的位置数。

下图为S=3时的情况
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";
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值