Codeforces 455B A Lot of Games:博弈dp【多局遊戲】

Leohh發表於2018-01-08

題目連結:http://codeforces.com/problemset/problem/455/B

題意:

  給你n個字串,然後進行k局遊戲。

  每局遊戲開始有一個空串,然後雙方輪流給這個串的末尾新增字元,並保證新字串是n個字串中至少一個串的字首。

  當一方不能新增字元時,這一方輸,遊戲結束。

  每場遊戲結束後,這場遊戲輸的人會成為下一句遊戲的先手。

  誰贏得了最後一場比賽,誰才會真正贏得比賽。

  問你最終真正贏得比賽的人,是第一局遊戲的先手還是後手(分別稱為First和Second)。

 

題解:

  先考慮單局遊戲。

 

  先對原來的n個串,建立一棵trie樹。

  那麼原遊戲就變成了:

    最初有一個棋子在根節點,雙方輪流將棋子向下移一格,不能移動的一方輸。

 

  因為每場遊戲都是一模一樣的,所以每場遊戲先手必勝還是必敗也是確定的。

  所以遊戲的最終贏家取決於,誰能夠拿到最後一場遊戲的必勝方。

  所以要求的也就不單單是先手是必勝還是必敗了。

  而是要分別求:先手能否必勝,和先手能否必敗。

  一遍dfs就能解決。

 

  然後分情況討論:

    (1)先手只能必勝,不能必敗:

      則奇數局的先手是First,First必勝。

      偶數局的先手是Second,Second必勝。

    (2)先手可以必勝,也可以必敗:

      那麼First會一直讓自己輸,一直讓自己是先手,直到最後一局再贏。

      所以此時First必勝。

    (3)先手不能必勝,只能必敗:

      也就是無論怎樣操作,First一直都是先手,所以Second必勝。

    (4)先手不能必勝,也不能必敗:

      也就是後手既可以必勝,也可以必敗。

      所以後手會一直讓自己贏,一直讓自己是後手,所以Second必勝。

 

AC Code:

 

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 100005
 5 #define MAX_L 100005
 6 #define MAX_A 30
 7 
 8 using namespace std;
 9 
10 struct Node
11 {
12     int nex[MAX_A];
13     Node()
14     {
15         memset(nex,0,sizeof(nex));
16     }
17 };
18 
19 int n,k;
20 int cnt=1;
21 bool win[MAX_L];
22 bool lose[MAX_L];
23 string s[MAX_N];
24 Node node[MAX_L];
25 
26 void read()
27 {
28     cin>>n>>k;
29     for(int i=1;i<=n;i++)
30     {
31         cin>>s[i];
32     }
33 }
34 
35 void init_trie()
36 {
37     for(int i=1;i<=n;i++)
38     {
39         int now=1;
40         for(int j=0;j<s[i].size();j++)
41         {
42             if(!node[now].nex[s[i][j]-'a'])
43             {
44                 node[now].nex[s[i][j]-'a']=++cnt;
45             }
46             now=node[now].nex[s[i][j]-'a'];
47         }
48     }
49 }
50 
51 void dfs(int now)
52 {
53     win[now]=lose[now]=false;
54     bool flag=true;
55     for(int i=0;i<26;i++)
56     {
57         if(node[now].nex[i])
58         {
59             dfs(node[now].nex[i]);
60             win[now]|=(!win[node[now].nex[i]]);
61             lose[now]|=(!lose[node[now].nex[i]]);
62             flag=false;
63         }
64     }
65     if(flag) lose[now]=true;
66 }
67 
68 void work()
69 {
70     init_trie();
71     dfs(1);
72     if(win[1] && !lose[1]) cout<<((k&1)?"First":"Second")<<endl;
73     else if(win[1] && lose[1]) cout<<"First"<<endl;
74     else cout<<"Second"<<endl;
75 }
76 
77 int main()
78 {
79     read();
80     work();
81 }

 

相關文章