HDU - 6370 Werewolf 推规律+拓扑判环+bfs

题意:

给定n个玩家,每个玩家只有两种身份;然后每个玩家说某一个玩家是人还是狼,

如果这个玩家是人,那他只会说真话;否则可能说假话可能说真话;

思路:

开始我们以为没法判断是否有确定的解,猜了0 0 不对,后来发现:

当两个玩家A,B:A说B是人,B说A是狼,那如果A是人的话,B就是狼,而A说B是人,矛盾,那么A不可能是人,即判定了A是狼

由此再推,三个,四个....玩家成环的情况,发现 只有这个环中指认狼的的个数唯一的时候,才能确定被指认的玩家是狼,

这一步骤用拓扑判环的方法,把环外面的链去掉;然后遍历每个环看是不是有符合条件的狼存在;

把所有的狼找出来后,然后找指认这个玩家是人的玩家,那他就是狼,因为他说了假话=-=

把狼加入队列,bfs跑一边找到所有的狼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,char> P;
const int maxn = 1e5 + 7;
P a[maxn];
int n, v, ans = 0;
int dig[maxn];
bool vis[maxn];
char s[10];
vector<int> vec[maxn];
queue<int> lang;

void solve(int id) {
  vis[id] = 1;
  int t = a[id].first;
  while(1) {
    dig[t]--;
    if(dig[t]) return;
    vis[t] = 1;
    t = a[t].first;
  }
}
void work(int id) {
  int t = id, u = -1, num = 0, cnt = 0;
  while(1) {
    if(vis[t]) break;
    vis[t] = 1;
    num++;
    if(a[t].second == 'v') cnt++;
    else u = a[t].first;
    t = a[t].first;
  }
  if(cnt == num-1) {
    //ans++;
    lang.push(u);
  }
}
void bfs() {
  while(!lang.empty()) {
    int t = lang.front(); lang.pop(); ans++;
    for(auto i : vec[t]) {
      if(a[i].second == 'v') lang.push(i);
    }
  }
}
int main() {
  int T; scanf("%d", &T);
  while(T--) {
      memset(dig, 0, sizeof dig);
      memset(vis, 0, sizeof vis);
      ans = 0;
      while(!lang.empty()) lang.pop();

    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) vec[i].clear();
    for(int i = 1; i <= n; ++i) {
      scanf("%d%s", &v, s);
      vec[v].push_back(i);
      a[i].first = v; a[i].second = s[0];
      dig[v]++;
    }
    for(int i = 1; i <= n; ++i) {
      if(vis[i]) continue;
      if(dig[i] == 0) solve(i);
    }
    for(int i = 1; i <= n; ++i) {
      if(!vis[i]) {
        work(i);
      }
    }
    bfs();
    printf("0 %d\n", ans);
  }

  return 0;
}


/*
4
4
2 w
1 v
4 v
3 w
3
2 v
3 v
1 w

*/

猜你喜欢

转载自blog.csdn.net/xiang_6/article/details/81514745