codeforces787C(存在平局的博弈+往前递推)

这篇博客讨论了codeforces787C的博弈问题,涉及两人轮流移动棋子的策略。当棋子位于2到n之间的点时,分析了先手玩家在不同位置的获胜策略。介绍了必胜态和必败态的概念,并阐述了如何通过反向递推确定游戏状态,从而解决存在平局的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题意,有n个点排成一个圈。有一个棋子,两个人轮流在各自集合选出一些数来移动棋子。将棋子移动到点1的人获胜,求棋子在2~n且两个人先手情况下的获胜情况

题解:
必胜态:后继状态对方有一个必败态
必败态:后继状态对方都是必胜态
平局:其他情况。因为我们已经不能必胜,但败更不优,所以其他情况就是平局。

那么我们可以设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i个人在 j j j个位置为先手的时候的状态,0为必败,1为必胜。但是我们并不能从后继状态推到出当前状态。我们最初只知道1位置是必败态,那么我们反向推就行了。如果当前状态为必败,那么前继状态为必胜。若当前状态为必胜,且其前继状态的所有后继状态都为必胜,那么它就为必败。否则除了以上两种情况都是平局。

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
const int maxn = 7005;
int n;
vector<int>V[2];
int dp[2][maxn];//第i个人在j状态下是什么情况,-1为平局
int d[2][maxn];//往前推,所以要记录有多少个必胜点 
void dfs(int p,int now,int sta){
	if(dp[p][now]!=-1)return;
	dp[p][now]=sta;
	if(sta==0){
		for(auto v:V[p^1]){
			int pre = (now-v+n)%n;
			if(!pre)continue;
			dfs(p^1,pre,1);
		}
	}
	else{
		for(auto v:V[p^1]){
			int pre = (now-v+n)%n;
			if(!pre)continue;
			if(++d[p^1][pre] == V[p^1].size())dfs(p^1,pre,0); 
		}
	} 
} 
string ans[]={"Loop","Lose","Win"};
int main(){
	memset(dp,-1,sizeof(dp));
	 cin>>n;
	 int k1,k2;
	 cin>>k1;
	 for(int i=1;i<=k1;i++){
	 	int t;cin>>t;
	 	V[0].push_back(t);
	 }
	 cin>>k2;
	 for(int i=1;i<=k2;i++){
	 	int t;cin>>t;
	 	V[1].push_back(t);
	 }
	 dfs(1,0,0);
	 dfs(0,0,0);
	 for(int i=1;i<n;i++){
	 	cout<<ans[dp[0][i]+1]<<" ";
	 }
	 puts(""); 
	 for(int j=1;j<n;j++){
	 	cout<<ans[dp[1][j]+1]<<" ";
	 }
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值