HDU6370 Werewolf(2018HDU多校联赛第六场,思路,dfs)

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≤T≤10
1≤N≤100,000
1≤x≤N
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

思路

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

  • 村民不会说谎
  • 狼人可能说谎

然后玩家有三种类型:

  1. 玩家在所有的情况下只能当村民
  2. 玩家在所有的情况下只能当狼人
  3. 玩家既可以当狼人也可以当村民

题目给出 n n <script type="math/tex" id="MathJax-Element-1">n</script>个玩家,然后给出若干条信息,例如”xxx说xxx是狼人”或者”xxx说xxx是村民”,现在题目想请你确定,第一种类型和第二中类型的玩家数量

首先我们知道,因为狼人可以说谎,所以假设所有的玩家全部是狼人,不论谁说谁是什么,游戏一定成立,他们都可以当狼人,也就证明了不存在“玩家在所有的情况下只能当村民”这种情况.

那么,我们可以做一个假设,假设全部的玩家都是狼人,那么第二种玩家类型的数量为总的玩家数量减去狼人中可以当村民的玩家数量。

那么问题就转化成了在所有的玩家都是狼人的时候,有多少人可以当村名。

我们可以先对题目给出的数据进行记录,记录一下每个人谁说他是狼人谁说他是村民的玩家数量。

我们首先对每一个玩家进行处理,比如,当玩家2说玩家1是狼人的时候,假设玩家1就是狼人,那么当玩家1是狼人的时候他不管说什么,都可以使游戏成立.这个时候我们就可以确定,玩家2可以当村民,那么玩家2当了村民,那么谁说玩家2是村民,那么这个人也可以当村民,这是一个递归的过程,在过程中用vis数组标记当前玩家已经有了确定的身份。但是在这个递归的过程中要注意,当递归出现环的时候,假设到了玩家5,玩家1说玩家5是村民,这个时候因为玩家1的身份是我们确定了的狼,所以玩家1不能被标记为村民,而且要把所有说玩家1是村民的玩家都标记一下。

最后我们就知道了这些狼人中哪些玩家可以做村民,然后用总数减去,再把所有玩家遍历一遍,减去没有被标记过的玩家,就是答案。

代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int N = 1e5 + 100;
/*
v1[i]:说第i个人是狼人的集合
v2[i]:说第i个人是村民的集合
*/
vector<int> v1[N], v2[N];
int vis[N];
void init()
{
    mem(v1, 0);
    mem(v2, 0);
    mem(vis, 0);
}
void dfs2(int u)
{
    for (auto num : v2[u])
    {
        vis[num] = 1;
        dfs2(num);
    }
}
int dfs(int u, int i)
{
    int ans = 0;
    for (auto num : v2[u])
    {
        vis[num] = 1;
        if (num != i)
            ans += dfs(num, i);
        else
            dfs2(num);
    }
    return ans + 1;
}
void solve()
{
    int n, x;
    char s[10];
    scanf("%d", &n);
    init();
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%s", &x, s);
        if (s[0] == 'w')
            v1[x].push_back(i);
        else
            v2[x].push_back(i);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (auto num : v1[i])
        {
            vis[num] = 1;
            ans += dfs(num, i);
        }
    }
    ans = n - ans;
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
            ans--;
    }
    printf("0 %d\n", ans);
}
int main()
{
    // freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while (t--)
        solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值