Werewolf

                                         Werewolf

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 262144/262144K (Java/Other)

Total Submission(s) : 1   Accepted Submission(s) : 1

Problem Description

"The Werewolves" is a popular card game among young people.In the basic game, there are 2 different groups: the werewolves and the villagers.

Each player will debate a player they think is a werewolf or not.

Their words are like "Player x is a werewolf." or "Player x is a villager.".

What we know is :

1. Villager won't lie.

2. Werewolf may lie.

Of cause we only consider those situations which obey the two rules above.

It is guaranteed that input data exist at least one situation which obey the two rules above.

Now we can judge every player into 3 types :

1. A player which can only be villager among all situations,

2. A player which can only be werewolf among all situations.

3. A player which can be villager among some situations, while can be werewolf in others situations.

You just need to print out the number of type-1 players and the number of type-2 players.

No player will talk about himself.

 

 

Input

The first line of the input gives the number of test cases T.Then T test cases follow. The first line of each test case contains an integer N,indicating the number of players. Then follows N lines,i-th line contains an integer x and a string S,indicating the i-th players tell you,"Player x is a S." limits: $ 1 \leq T \leq 10 $ $ 1 \leq N \leq 100,000 $ $ 1 \leq x \leq N $ $ S \in $ {"villager"."werewolf"}

 

 

Output

For each test case,print the number of type-1 players and the number of type-2 players in one line, separated by white space.

 

 

Sample Input


 

1 2 2 werewolf 1 werewolf

 

 

Sample Output


 

0 0

 

 

Source

2018 Multi-University Training Contest 6

先说题意,在狼人杀游戏中,有两种角色,一种是狼人另一种是村民,他们的特征是:

村民不会说谎
狼人可能说谎
然后玩家有三种类型:

玩家在所有的情况下只能当村民
玩家在所有的情况下只能当狼人
玩家既可以当狼人也可以当村民
题目给出nn个玩家,然后给出若干条信息,例如”xxx说xxx是狼人”或者”xxx说xxx是村民”,现在题目想请你确定,第一种类型和第二中类型的玩家数量

给一个场上出的样例,1说2是农民,2说1是狼人。这样的话,可以判断出1一定是狼人,因为若1是农民,讲真话,2也是农民,讲真话,1是狼人,矛盾了。

再者说,1说2是农民,2说3是农民,3说4是农民,4说1是狼人,那么1一定是狼人,证明同上。

于是我们可以给出一个推广,如果你被一个人认定是狼人,并且这个人还是你认定的农民,或者是被你间接认定的农民,那么,你一定是狼

再者,如果判断出我是狼人,那么说我是农民的人也一定是狼人。

因此,到这里这个题就可以写了。

我们使用并查集来写,刚开始我们只连接进去农民边,记录出来狼人边,最后加进去狼人边,如果狼人边的两端在同一个并查集内,则会产生狼人,首先被认定的人是狼人,其次,指向我的人是狼人,代码中v数组记录是都有谁指向我是农民,fa[]记录的是我指向的下一个人,Q用来寻找指向我是农民的人。如果狼人边的两端在不同的并查集,可以忽略不管,为什么呢,因为咱们假如x认定y是狼人,但是y在另一个并查集中,此时咱们想如果只有y是狼人,此时x整个并查集中时农民,y并查集中有狼人,这样式成立的,但是如果x并查集中是狼人,y并查集中时农民,答案也是成立的,因此这种情况下,没有一定的狼人
 

#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
const int maxn=100005;
int t,n,fa[maxn];
int ans;
vector <int> V, v[maxn];
queue<int> Q;

void init()
{
    ans = 0;
    V.clear();
    for(int i = 1 ; i <= n ; i++)
    {
        fa[i] = i;
        v[i].clear();
    }
    while(!Q.empty())
        Q.pop();
}

int Find(int x)
{
    if(x==fa[x])
    {
        return x;
    }
    return fa[x]=Find(fa[x]);
}
void un(int u,int v)
{
    int fu,fv;
    fu = Find(u);
    fv = Find(v);
    if(fu != fv)
        fa[fu] = fv;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        init();
        int tmp;
        char s[20];
        for(int i = 1; i <=n ;i++)
        {
            scanf("%d",&tmp);
            scanf("%s",s);
            if(s[0]=='v')
            {
                un(i,tmp);
                v[tmp].push_back(i);
            }
            else
            {
                V.push_back(i);
                V.push_back(tmp);
            }
        }
        for(int i = 0 ; i <= V.size() -1 ;i++)
        {
            int a,b;
            a = V[i];
            b = V[++i];
            if(Find(a)==Find(b))
            {
                Q.push(b);
                while(!Q.empty())
                {
                    int f = Q.front();
                    Q.pop();
                    ans++;
                    for(int j = 0 ; j < v[f].size();j++)
                        Q.push(v[f][j]);
                }

            }
        }
        if(n==1)
            printf("0 0\n");
        else
            printf("0 %d\n",ans);
    }
    return 0;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章