其他分享
首页 > 其他分享> > Werewolf

Werewolf

作者:互联网

题目链接

思路:首先这是一个最大出度为1的有向图。有两种不同的边,狼边和村民边。假设都是狼,这显然是成立的,那么必为村民的个数就为0。那么必为狼的个数呢?这题的关键突破口是,形成一个村民环,只有一条狼边,那么狼边指向的那个节点必为狼,所有指向铁狼的村民边也比为狼(分析如下)。其他情况必为狼的数目为0。

假设A为村民,因为村民不说谎,那么B,C,D为村民,D为村民得出A为狼,矛盾,所以A为狼。

那么知道这个如何判断成环?如何求出指向铁狼的村民边的条数呢?反向建图,vector <int> G [maxn]保存节点保存指向i节点的村民边,用并查集把所有的村民边合并,用V保存狼边,如果狼边连接着的两个节点在同一个村民联通块中,说明形成了环,dfs狼边指向的那个节点,统计到答案中即可。

#include <bits/stdc++.h>
#define pi pair<int,int>
#define mk make_pair
#define ll long long
using namespace std;

const int maxn = 1e5+100;

vector<pi>V;
vector<int>G[maxn];
int p[maxn],vis[maxn];
ll ans;

void init(int n)
{
    ans = 0;
    for(int i = 1; i <= n; i++)
        G[i].clear(),p[i] = i,vis[i] = 0;
    V.clear();
}
int find(int x)
{
    return x == p[x]? x : p[x] = find(p[x]);
}

void dfs(int u)
{
    if(vis[u] == 1)return ;
    vis[u] = 1;
    ++ans;
    for(auto v : G[u])
        dfs(v);
}
int main()
{
    int T,n,x;
    scanf("%d",&T);
    while(T--)
    {
        char op[10];
        scanf("%d",&n);
        init(n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%s",&x,op);
            if(op[0] == 'v')
                G[x].push_back(i);
            else V.push_back(mk(i,x));
        }

        for(int i=1;i<=n;i++)
        {
            for(auto it : G[i])
            {
                int u = find(i);
                int v = find(it);
                if(u != v)p[u] = v;
            }
        }
        for(auto it : V)
        {
            int u = it.first;
            int v = it.second;
            if(find(u) == find(v))dfs(v);
        }
        printf("0 %lld\n",ans);
    }
}

 

 

OerUUU 发布了35 篇原创文章 · 获赞 20 · 访问量 1071 私信 关注

标签:村民,Werewolf,int,狼边,maxn,必为,节点
来源: https://blog.csdn.net/weixin_44499508/article/details/103943816