Codeforces Round #406 (Div. 2) C 博弈

来源:互联网 发布:吉利电动车知豆d2价钱 编辑:程序博客网 时间:2024/06/10 05:28

题目链接

此题类似于当初上ACM公选课博弈一节的某例题,考察了对于必胜点,必败点等基础知识的掌握。

对于此题:

必败点(P点) :前一个选手(Previous player)将取胜的位置称为必败点。
必胜点(N点) :下一个选手(Next player)将取胜的位置称为必胜点。

对于必败点和必胜点,分别有以下性质:

必败点:无论怎么操作,从必败点下一步都只能进入必胜点。
必胜点:至少存在一种操作,能从必胜点走到必败点。

上述概念看似有点抽象,对于本题,简单理解就是:
当轮到某玩家操作时,无论怎么操作,操作结束后都是对方胜利,此时就是必败点。考虑特殊例子的话,当棋子已经走到了 1 的点,游戏已经结束,这时对于下一个操作的人此时就是必败点。
而如果轮到某玩家操作时,他有多种不同的操作选择,但存在一种操作使得他选择后,对方无论怎么操作都是输,即使对方进入必败点,则该玩家此时处于必胜点。

所以对于本题,我们可以考虑在时间轴上从后往前BFS,因为游戏结束有着明确的规定,即棋子移动到了 1 的点。若棋子已经在 1 的点,则谁先手谁就已经输了(因为在先手操作前棋子已经到达1,则说明是后手达到胜利条件)。

以 1 作为必败点,从后往前搜索,则存在两种情况:
(1).当前状态为必败点。
则上一个状态必为必胜点。(如果某一个状态通过某一个操作能走到必败点,则该点一定是必胜点)
(2).当前状态为必胜点。
此时情况便复杂一点,因为此时有两种可能:

必胜点 --> 必胜点必败点 --> 必胜点

故我们可以用一个数组保存某个点到达必胜点的次数,若能够达到必胜点的次数等于总的操作数,即无论怎么操作,都只能从当前状态到达必胜点。
则当前状态为必败点。

则便是我下面代码里面的出度数组: deg[]
因为总的操作数是 k1 / k2,故我们可以提前预处理deg数组为总的操作数,一旦能够到达某一个必胜点,则出度减一,当出度为0时,则达到了上述条件。

然后没有更新答案的点就是可以为圈的点。
代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 1e9 + 7;const int A = 1e4 + 100;class P{public:    int pos,k;    P(int i,int j):pos(i),k(j){}};int val_1[A],val_2[A];int deg_1[A],deg_2[A];int ans_1[A],ans_2[A];  // 1 必败 2 必胜queue<P> que;int main(){    int n;    scanf("%d",&n);    int k1,k2;    scanf("%d",&k1);    for(int i=1 ;i<=k1 ;i++) scanf("%d",&val_1[i]);    scanf("%d",&k2);    for(int i=1 ;i<=k2 ;i++) scanf("%d",&val_2[i]);    ans_1[1] = ans_2[1] = 1;    que.push(P(1,1)),que.push(P(1,2));    for(int i=1 ;i<=n ;i++){        deg_1[i] = k1;        deg_2[i] = k2;    }    deg_1[1] = deg_2[1] = INF;    while(que.size()){        P now = que.front();que.pop();        if(now.k == 1){            for(int i=1 ;i<=k2 ;i++){                int ne = (now.pos - val_2[i] - 1 + n) % n + 1;   //避免产生0                if(ans_2[ne]) continue;                if(ans_1[now.pos] == 1){                    ans_2[ne] = 2;                    que.push(P(ne,2));                }                else{                    deg_2[ne]--;                    if(deg_2[ne] == 0){                        ans_2[ne] = 1;                        que.push(P(ne,2));                    }                }            }        }        else{            for(int i=1 ;i<=k1 ;i++){                int ne = (now.pos - val_1[i] - 1 + n) % n + 1;                if(ans_1[ne]) continue;                if(ans_2[now.pos] == 1){                    ans_1[ne] = 2;                    que.push(P(ne,1));                }                else{                    deg_1[ne]--;                    if(deg_1[ne] == 0){                        ans_1[ne] = 1;                        que.push(P(ne,1));                    }                }            }        }    }    for(int i=2 ;i<=n ;i++){        if(ans_1[i] == 2) printf("Win ");        else if(ans_1[i] == 1) printf("Lose ");        else    printf("Loop ");    }    puts("");    for(int i=2 ;i<=n ;i++){        if(ans_2[i] == 2) printf("Win ");        else if(ans_2[i] == 1) printf("Lose ");        else    printf("Loop ");    }    return 0;}
0 0
原创粉丝点击