字典樹+博弈 CF 455B A Lot of Games(接龍遊戲)

 

題目連接c++

題意:數組

  A和B輪流在建造一個字,每次添加一個字符,要求是給定的n個串的某一個的前綴,不能添加字符的人輸掉遊戲,輸掉的人先手下一輪的遊戲。問A先手,通過k輪遊戲,最後勝利的人是誰。code

思路:blog

  很顯然先將n個字符串插入到字典樹上,由於字典樹上有分叉,不能僅僅判斷字符串長度奇偶性來判斷。字典樹當作無環的狀態圖,若是按照拓撲排序逆序進行排序,在判斷每一個節點的時候,它的後繼都已經判斷過了。定義兩個數組can_win[u], can_lose[u],表示u節點走下去「可能贏嗎?」以及u節點走下去」可能輸嗎?「,那麼取反就是必勝和必敗態了,「可能贏」<-對手下一步不可能贏,」可能輸「<-對手下一步不可能輸。排序

代碼:遊戲

#include <bits/stdc++.h>

const int N = 1e5 + 5;
char str[N];
int ch[N][26];
int sz;

bool can_win[N], can_lose[N];

void init() {
    memset (ch[0], 0, sizeof (ch[0]));
    sz = 1;
}

void insert(char *s) {
    int u = 0, c;
    for (int i=0; s[i]; ++i) {
        c = s[i] - 'a';
        if (!ch[u][c]) {
            memset (ch[sz], 0, sizeof (ch[sz]));
            ch[u][c] = sz++;
        }
        u = ch[u][c];
    }
}

void DFS(int u) {
    can_win[u] = can_lose[u] = false;
    bool is_leaf = true;
    for (int c=0; c<26; ++c) {
        int v = ch[u][c];
        if (v) {
            is_leaf = false;
            DFS (v);
            can_win[u] |= !can_win[v];
            can_lose[u] |= !can_lose[v];
        }
    }
    if (is_leaf) {
        can_lose[u] = true;
    }
}

int main() {
    int n, k;
    scanf ("%d%d", &n, &k);
    init ();
    for (int i=0; i<n; ++i) {
        scanf ("%s", str);
        insert (str);
    }
    
    DFS (0);

    if (!can_win[0]) {
        puts ("Second");  //of course!
    } else if (can_lose[0]) {
        puts ("First");  //can lose && can win, control!
    } else {
        //can win && !can lose, change A and B every turn!
        printf ("%s\n", (k & 1) ? "First" : "Second");
    }
    return 0;    
}
相關文章
相關標籤/搜索