HDU 6370 Werewolf 并查集+BFS

题意

狼人游戏。狼人可能说谎,村民不会说谎。N个人每个人说一句话,“x是狼人”或者“x是村民”。
求一定是村民的人的数量,一定是狼人的人的数量。

题解

因为狼人可以不说谎,即狼人可以伪装成村民,故不存在一定是村民的人。
然后,如果A说B是村民,B说A是狼人,那么A一定是狼人。

同样,如果A说B是村民,B说C是村民,C说A是狼人,那么A一定是狼人。总而言之,一个N条边的环,有N-1条村民边,1条狼人边,那么狼人边所指认的狼人一定就是狼人。

根据确定的狼人,指认狼人为村民的人也一定是狼人。

我们可以将这些指认关系建边,狼人边用边权1表示,村民边用边权0表示。将所有的村民边合并到并查集中。对所有的狼人边进行查询,如果边两端在一个集合中,那么它们形成了一个环。这个环中有N条边,其中N-1条村民边,1条狼人边。

将查询出来的狼人放入队列中,然后沿着指认狼人为村民的边进行BFS计数即可。

AC代码

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+7;
struct edge
{
    int from,to,next,w;//w=1表示狼
}e[maxn];
int head[maxn],cnt;
void init()
{
    memset(head,-1,sizeof(head));
    cnt=-1;
}
void add_edge(int u,int v,int w)
{
    e[++cnt].to=v;
    e[cnt].from=u;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
int par[maxn];
int find(int x)
{
    return par[x]==x?x:find(par[x]);
}
void unit(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return ;
    par[fx]=fy;
}
bool vis[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        init();
        for(int i=0;i<=n;i++) par[i]=i;
        for(int i=1;i<=n;i++)
        {
            int x;
            char s[20];
            scanf("%d%s",&x,s);
            if(s[0]=='w') add_edge(x,i,1);
            else add_edge(x,i,0),unit(x,i);//村民边合并以判环
        }
        memset(vis,false,sizeof(vis));
        queue<int> que;
        int ans=0;
        for(int i=0;i<=cnt;i++)
        {
            int u=e[i].from,v=e[i].to,w=e[i].w;
            if(find(u)==find(v) && w==1 && !vis[u])
            {
                vis[u]=true;
                ans++;
                que.push(u);
            }
        }
        while(!que.empty())
        {
            int u=que.front();que.pop();
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v=e[i].to,w=e[i].w;
                if(vis[v]) continue;
                if(w) continue;
                vis[v]=true;
                ans++;
                que.push(v);
            }
        }
        printf("0 %d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/81532149