我是靠谱客的博主 现实砖头,最近开发中收集的这篇文章主要介绍AtCoder Beginner Contest 209 E - Shiritori(博弈,图),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

LINK

Takahashi先手(叫做小 T T T),Aoki后手(叫做小 A A A)

每个人轮流说一个单词,这个单词的前三个字母必须等于上一个单词的后三个字母

现在问当小 T T T说出的第一个单词为 s i s_i si时,能否获得胜利??


可以 O ( n 2 ) O(n^2) O(n2)暴力枚举两点间是否有边,但是复杂度太高

考虑每个单词只有前三个字母和后三个字母有用

把前三个字母浓缩成一个点,后三个字母浓缩成一个点

那么单词 s i s_i si(设长度为 l l l)就表示能从 { s 1 , s 2 , s 3 } {s_1,s_2,s_3} {s1,s2,s3}转移到 { s l − 2 , s l − 1 , s l } {s_{l-2},s_{l-1},s_l} {sl2,sl1,sl}

这样整个图只有 n n n条边

T T T选定第一个单词为 s i s_i si,在我们构造的图中相当于是以 { s l − 2 , s l − 1 , s l } {s_{l-2},s_{l-1},s_l} {sl2,sl1,sl}点为起始点的胜负状态

如果这个图是个DAG,问题就变得非常简单,拓扑排序一下就好了.

令状态 0 0 0表示先手赢,状态 1 1 1表示后手赢,状态 2 2 2表示平局

i i i的所有后继都是先手赢,那么 f [ i ] = 1 f[i]=1 f[i]=1,先手必败

i i i存在后继是后手赢,那么 f [ i ] = 0 f[i]=0 f[i]=0,先手必胜

但是这个图可能有环,不过还是可以一样的拓扑排序…

但是当一个点度为零确定状态时就入队

最后没状态的就是平局

#include <bits/stdc++.h>
using namespace std;
const int M = 52*52*52;
int z(char c)
{
    if('A'<=c && c<='Z') return c-'A';
    else return c-'a'+26;
}
int trans(char a,char b,char c)
{
    return z(a) * 52 * 52 + z(b) * 52 + z(c);
}
int in[M];
int main()
{
	int n; cin >> n;
	vector<pair<int,int>> edge(n);
	vector<vector<int> > revGraph(M);
	for(int i=0;i<n;i++)
	{
		string s; cin >> s;
        edge[i] = make_pair(trans(s[0], s[1], s[2]), trans(s[s.size()-3], s[s.size()-2], s[s.size()-1]));
        in[edge[i].first]++;
        revGraph[edge[i].second].push_back(edge[i].first);		
	}
    vector<int> ans(M, -1);
    queue<int> que;
    for(int i = 0; i < M; i++) 
		if( in[i] == 0)
		{
        	ans[i] = 0;//赢 
        	que.push(i);
    	}
    while(!que.empty()) 
	{
        int t = que.front(); que.pop();
        for(int x : revGraph[t] )
		{ 
			if(ans[x] == -1) 
			{
	            in[x]--;
	            if(ans[t] == 0)
	                ans[x] = 1, que.push(x);
	            else if( in[x] == 0)
	                ans[x] = 0, que.push(x);
	        }
	    }
    }
    for(int i = 0; i < n; i++) 
	{
        if(ans[edge[i].second] == -1) cout << "Draw" << endl;
        if(ans[edge[i].second] == 0) cout << "Takahashi" << endl;
        if(ans[edge[i].second] == 1) cout << "Aoki" << endl;
    }	
}

最后

以上就是现实砖头为你收集整理的AtCoder Beginner Contest 209 E - Shiritori(博弈,图)的全部内容,希望文章能够帮你解决AtCoder Beginner Contest 209 E - Shiritori(博弈,图)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部