Codeforces Round #260 (Div. 1) B. A Lot of Games Trie + 博弈

题意:两个人在Trie树上博弈k局,当前局输的人在下一局中执先手。在一局博弈中,当一个人不能走时,判定另一个人赢。最后一局的结果作为整个游戏的结果。

分析:先手赢的情况为:(1)先手可必胜,也 可败。那么前k-1局败,最后一局胜利即可。

(2)先手只能必胜。 当k为奇数时获胜。

   后手赢的情况为:(1)先手必败。

(2)先手只能必胜。 k为偶数。


(本题的状态为取完当前节点的状况)

判定先手是否可必胜:叶子节点为可必胜。如果一个节点的后继存在必胜,那么此节点为必败。如果一个节点的后继全为必败,那么此节点为必胜。


那么判定是否可败也是这样类似:叶子节点为不可败。如果一个节点的后继存在可败,那么此节点为不可败。如果一个节点的后继全为不可败,那么此节点为可败。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int ALP=26;
struct Trie{
    int next[maxn][ALP],dp[maxn],dp2[maxn];
    int root,p;
    int newnode(){
        for(int i=0;i<ALP;i++)
            next[p][i] = -1;
        return p++;
    }
    void init(){
        p = 0;
        root = newnode();
    }
    void insert(char *buf){
        int len = strlen(buf);
        int now = root;
        for(int i=0;i<len;i++){
            int c = buf[i]-'a';
            if(next[now][c]==-1)
                next[now][c] = newnode();
            now = next[now][c];
        }
    }
    int dfs(int x){
        int co=0 , win = 0;
        for(int i=0;i<ALP;i++)if(next[x][i]!=-1){
            int u = next[x][i];
            win += dfs(u);
            co++;
        }
        if(co==0) return dp[x] = 1;
        else if(co>0 && win>0) return dp[x] = 0;
        else return dp[x] = 1;
    }
    int dfs2(int x){
        int co=0, fail = 0;
        for(int i=0;i<ALP;i++)if(next[x][i]!=-1){
            int u = next[x][i];
            fail += dfs2(u);
            co++;
        }
        if(co==0) return dp2[x] = 0;
        else if(co>0 && fail==0) return dp2[x] = 1;
        else return dp2[x] = 0;
    }
    void solve(int k){
        int ok1=0 , ok2=0;
        dfs(root);
        for(int i=0;i<ALP;i++)if(next[root][i]!=-1){
            int u = next[root][i];
            if(dp[u]==1) ok1 = 1;
        }
        dfs2(root);
        for(int i=0;i<ALP;i++)if(next[root][i]!=-1){
            int u = next[root][i];
            if(dp2[u]==1) ok2 = 1;
        }
        if(ok1==0){
            puts("Second");
        }else{
            if(ok2==0){
                if(k&1) puts("First");
                else puts("Second");
            }else{
                puts("First");
            }
        }
    }
}tr;
char s[maxn];
int main(){
    int n,k;
    tr.init();
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        tr.insert(s);
    }
    tr.solve(k);
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值