题目链接 :http://codeforces.com/contest/456/problem/D
题目大意:已经给定了一组字符串(字典),然后两个人玩游戏。两个人轮流操作一个字符串,一开始字符串为空,每次一个人向这个字符串末尾添加一个字母,要求添加完毕后这个字符串必须是字典中的某个字符串的前缀,不能操作者为输。这样子视作一次游戏,一共进行K次相同的游戏,第I次游戏的失败方为第I+1次游戏的先手方。赢得第K次游戏的玩家为最终的赢家。问第1次游戏的先手方是最后的胜者还是第1次游戏的后手方是最后的胜者。
题解:将整个字典建成一棵字典树,单次游戏就变成了一个简单的博弈模型。DFS即可得先手方是否有必胜的策略,是否有必输的策略。
如果先手方既有必胜的策略又有必输的策略,则先手必胜。如果先手方既没有必胜的策略又没有必输的策略,后手必胜。如果先手方没有必胜的策略只有必输的策略,后手必胜。如果先手方有必胜的策略但没有必输的策略,当游戏总数为奇数时先手必胜,游戏次数为偶数时后手必胜。
博弈模型:对于一个状态,如果它的后继均为必胜态,则这个状态为必败态,否则这个状态是必胜态。#include <iostream>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <stack>
#include <vector>
using namespace std;
struct point
{
point * next[26];
point()
{
for (int i=0;i<26;i++)
{
next[i]=NULL;
}
}
};
void insert(point* root ,string s)
{
point *p=root;
for (int i=0;i<s.length();i++)
{
if (p->next[s[i]-97]==NULL)
{
p->next[s[i]-97]=new(point);
}
p=p->next[s[i]-97];
}
return ;
}
void clear(point *p)
{
for (int i=0;i<26;i++)
{
p->next[i]=NULL;
}
}
int DW1(point* p)
{
int mex[27]={0};
for (int i=0;i<26;i++)
{
if (p->next[i]!=NULL)
{
mex[DW1(p->next[i])]=1;
}
}
for (int i=0;i<27;i++) if (!mex[i]) return i;
}
int DW2(point* p)
{
int mex[27]={0};
bool f=false;
for (int i=0;i<26;i++)
{
if (p->next[i]!=NULL)
{
f=true;
mex[DW2(p->next[i])]=1;
}
}
if (!f) return 1;
for (int i=0;i<27;i++) if (!mex[i]) return i;
}
int main()
{
point* root=new(point);
int n,k;
int k1,k2;
string s;
while (~scanf("%d%d",&n,&k))
{
clear(root);
for (int i=0;i<n;i++)
{
cin>>s;
insert(root,s);
}
k1=DW1(root);
k2=DW2(root);
// cout<<k1<<" "<<k2<<endl;
if (k1&&k2) printf("First\n");
else if (!k1&&!k2) printf("Second\n");
else if (k1&&!k2)
{
if (k%2) printf("First\n");
else printf("Second\n");
}
else printf("Second\n");
}
return 0;
}