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