http://acm.hdu.edu.cn/showproblem.php?pid=6370
分析:
思路:首先所有人都是狼一定合法,所以村民无法确定。经过一番推理,发现只有两种情况可以确定狼:
1、某些人的发言构成一个环,环上只有一个人发言说xxx是狼,其他的都说是村民。那么被说是狼的这个人一定是狼。
2、由1确定狼以后,有人说1确定的狼是人,那么这个人就一定是狼。(因为村民不会说谎)
暴力找环
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int maxn=100010;
int n,m,k;
int vis[maxn];
int id[maxn],c[maxn];
bool a[maxn];
int ans,ct,cnt,tmp,f,flag;
char s[maxn];
vector<int>vc[maxn];
queue<int>q;
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ans=0;tmp=0;
for(int i=1;i<=n;i++)
{
vis[i]=0;
a[i]=false;
vc[i].clear();
}
for(int i=1;i<=n;i++)
{
scanf("%d",&id[i]);//记录i说的编号
scanf("%s",s);
if(s[0]=='w') c[i]=1;
else {c[i]=0;vc[id[i]].push_back(i);}//i说id[i]是人
//确定出来是狼,那么说他是人的一定是狼
}
f=0;
for(int i=1;i<=n;i++)
if(!vis[i]){
cnt=0;
int j=id[i];
f++;//第几个环
vis[i]=f;
while(1)
{
if(vis[j]==inf) break;//在某个环上出现了,就不找了
if(vis[j]==f)//每个人都出一条边一定有环
{
cnt=0;
vis[j]=inf;//每个点只能出现在一个环上,出现在某个环上标记一下
int k=id[j];
if(c[j]) cnt++;
while(1)
{
vis[k]=inf;
if(c[k]) {cnt++;flag=id[k];}
k=id[k];
if(k==j) break;
}
if(cnt==1)
{
tmp++;a[flag]=1;
for(int tt=0;tt<vc[flag].size();tt++)
{
q.push(vc[flag][tt]);//说铁狼是人的那个东西的编号;他一定是狼
}
}
break;
}
//cout<<"*";
vis[j]=f;
j=id[j];
}
}
while(!q.empty()){
int k=q.front();q.pop();
tmp++;
for(int tt=0;tt<vc[k].size();tt++)
{
q.push(vc[k][tt]);//说铁狼是人的东西的编号;
}
}
printf("%d %d\n",ans,tmp);
// if(flag) puts("Yes"); else puts("No");
}
return 0;
}