题意,有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;
}