Codeforces Round #260 (Div. 2) D. A Lot of Games

题目链接 :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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值