HDU 6370 Werewolf 狼人杀(dfs)

16 篇文章 0 订阅
2 篇文章 0 订阅

题面

"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≤T≤101≤T≤10

1≤N≤100,0001≤N≤100,000

1≤x≤N1≤x≤N

S∈S∈ {"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

题目链接

HDU 6370 Werewolf

题意理解: 

  •  首先这道题是没有预言家,没有猎人,没有丘比特,没有………………只有狼人和村民
  • 每个人有一次说话机会,也只会指认一个人,不能同时指认两个人
  • 真话:狼人能说、村民也能说
  • 假话:只有狼人能说,村民不能说
  • 没有鼻祖村民、无法判断其他人是不是村民
  • 指认狼人是村民的人一定是狼。

分析:

  1. A和B 互相指认的时候可以判断其中一个人身份。两人互指有三种情况。
  2. 如图1:A指B为村民,B指A为村民。无法判断,此情况舍去。
  3. 如图2:A指B为狼人,B指A为狼人。无法判断,此情况舍去。
  4. 如图3:A指B为村民,B指A为狼人。A一定是狼人。得出结论:两人互指,被指出的身份不同,被指狼人的一定是狼人。
  5. 推广上述结论:在一个循环指认中,如果只有一人被指狼,那么他一定是狼。
  6. 证明:如图4,假设 1号 为村民,那么 2号 为村民、3号为村民……m-1号为村民、m号为村民、1号为狼人。与假设不符。
  7. 所以,如图5,在循环指认中,只有1号是狼人。
  8. 用上述方法判断出一些狼人后,可以用dfs找出说狼人是村民的人,这些人一定是狼人。


比赛时没有ac此题的原因:队友用之前用过的变量来记录答案,在记录答案之前没有清零。


程序分析

say[]数组:记录每个人说的话

what结构体:object表示指认对象。kind为true, 表示第i个人说指认对象是村民,反之则是狼

vill[]:记录说自己是村民的人有哪些。

s[]:读入“werewolf”  /   "villegers"

judge:判断此人说是狼人的人是不是狼人。

visit[]:dfs中用于记录访问过的人。

fina[]:记录所有被判断出是狼人的人。

sign[]:记录通过循环指认判断出是狼人的人。

#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
#define maxn 100000
struct what
{
    int object;
    bool kind;
};
vector<int>vill[maxn+10];
what say[maxn+10];
char s[10];
bool sign[maxn+10];
bool judge;
int visit[maxn+10];
bool fina[maxn+10];

void walk(int x,int i,int n)
{
    if(x==n&&i!=1)
    {
        judge=true;
        return;
    }
    if(say[x].kind==false&&i!=1)
        return;
    else
    {
        if(visit[say[x].object]&&say[x].object!=n&&i!=2)
            return;
        visit[say[x].object]=1;
        walk(say[x].object,i+1,n);
        visit[say[x].object]=0;
    }
}

void dfs(int x)
{
    if(vill[x].size()==0)
        return ;
    for(int i=0;i<vill[x].size();i++)
    {
        fina[vill[x][i]]=1;
        dfs(vill[x][i]);
    }
}


int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        what temp;
        memset(visit,0,sizeof(visit));
        memset(sign,0,sizeof(sign));
        memset(fina,0,sizeof(fina));
        for(int i=1;i<=n;i++)
        {
            scanf("%d%s",&say[i].object,s);
            if(s[0]=='w')
                say[i].kind=false;
            else if(s[0]=='v')
                say[i].kind=true;
            if(say[i].kind==true)
                vill[say[i].object].push_back(i);
        }
        for(int i=1;i<=n;i++)
        {
            if(say[i].kind==false)
            {
                judge =false;
                visit[i]=1;
                walk(i,1,i);
                visit[i]=0;
                if(judge==true)
                    sign[say[i].object]=true;
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(sign[i]==true)
            {
                fina[i]=true;
                dfs(i);
            }
        }
        int answer=0;
        for(int i=1;i<=n;i++)
        {
            if(fina[i]==1)
                answer++;
            vill[i].clear();
        }
        printf("0 %d\n",answer);
    }
    return 0;
}

2018年08月10日 08:52:34

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值