首先题意:有n个玩家每个玩家说一句话.话是 数字n+猜测身份.输出最少可能的人和狼。人必须说真话,狼可说真可说假
.首先如果都是狼,显然有这种可能,所以人最少就是0了。
第二我们能从一只狼推出另一只.说铁狼不是狼的一定是狼(人不能说假话)如何找铁狼呢?
先从简单的开始.如果没有头绪可以分析一下题.狼说的话可真可假.人必须说真话!那狼的话便没有用.需要从人的话开始分析.那如果只有两玩家,当A说B是人,B说A是狼.如果A是人.那此时B说A是狼.显然矛盾.这样A的狼身份就坐实.这种假设需要扩展.可能有许多玩家,这种判断过程可以扩展的是A说B是人的环节.只要A信任的人信任最后到了B,而B却认为A是狼.A此时就是铁狼.
然后加上我们一开始意识到的说铁狼不是狼的一定是狼.算出所有狼的个数.
想完了写的时候却很头疼.
#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <math.h>
#include <iomanip>
#include <queue>
#include <map>
#define sd(qwe) scanf("%d",&qwe)
#define se(cvb) scanf("%lf",&cvb)
#define ss(asd) scanf("%s",asd)
#define sc(xcv) scanf("%c",&xcv)
#define xh(ert,rty,tyu) for(int ert=rty;ert<=tyu;ert++)
#define fxh(u,i,o) for(int u=i;u>=o;u--)
#define maxn 200005
using namespace std;
int num,ans,head[maxn],f[maxn],vis[maxn];
struct Edge
{
int s,p,next,w;
}edge[maxn];
int findf(int s)
{
if(s==f[s])return s;
else return f[s]=findf(f[s]);
}
void addEdge(int s,int p,int w)
{
edge[num].s=s;edge[num].p=p;edge[num].w=w;edge[num].next=head[p];head[p]=num++;
}
void Union(int s,int p)
{
if(findf(p)==findf(s))return;
else f[findf(p)]=findf(s);
}
int main()
{int k;sd(k);
while(k--)
{
int p;sd(p);
ans=0;num=0;
memset(head,-1,sizeof(head));
xh(i,1,p)f[i]=i;
xh(i,1,p){
int d;sd(d);
char str[10];ss(str);
if(str[0]=='w')addEdge(i,d,1);else{addEdge(i,d,0);Union(i,d);}
}
memset(vis,0,sizeof(vis));
queue<int>que;
xh(i,0,num-1)
{int s=edge[i].s,w=edge[i].w,p=edge[i].p;
if(findf(s)==findf(p)&&w==1&&!vis[p])
{
ans++;
que.push(p);vis[p]=1;
}
}
while(!que.empty())
{
int fuck=que.front();que.pop();
for(int i=head[fuck];i!=-1;i=edge[i].next)
{
int s=edge[i].s,w=edge[i].w;
if(w)continue;
if(vis[s])continue;
ans++;
que.push(s);
}
}
printf("0 %d\n",ans);
}
return 0;
}