1. 程式人生 > >2018 Multi-University Training Contest 6 I Werewolf【博弈】

2018 Multi-University Training Contest 6 I Werewolf【博弈】

n個人互相說話,有的人是民(實話實說),有的人是狼(胡言亂語)。請判斷有多少人的身份可以確定。

根據題意,仔細思考可以發現,如果A說B是狼,B說A是民。那麼B是鐵狼。
假設B是民,則A是民,則A話有矛盾,故B是狼。

推廣開來,如果一條鏈上都是民,突然出現一個狼邊指向了起始點(成環),那麼民邊上的都是狼。

再推廣開來,通過鐵狼,可以推廣出更多的狼。

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
const int maxn = 1e5+55;

struct
node { int to; int kind; }len[maxn]; int ru[maxn],vis[maxn]; int pre[maxn],ed[maxn]; int tm, aim, ans; int flag[maxn]; void dfs(int x,int tm) { if(vis[x]) { if(vis[ed[x]] == tm){ aim = ed[x]; } return; } vis[x] = tm; int to = len[x].to; if
(len[x].kind == 1){ pre[to] = x; if(flag[to] == 1){ aim = x; return; } dfs(to, tm); ed[x] = ed[to]; }else{ if(vis[to] == tm) aim = to; ed[x] = to; return; } } int main() { int T; scanf("%d",&T); char
s[22]; while(T--){ int n;scanf("%d",&n); ans = tm = 0; for(int i=1;i<=n;i++){ pre[i] = 0; vis[i] = 0; ru[i] = flag[i] = 0; } for(int i=1;i<=n;i++){ int x; scanf("%d",&x); len[i].to=x; scanf("%s",s); if(s[0] == 'v'){ len[i].kind = 1; ru[x]++; }else{ len[i].kind = 0; } } for(int i=1;i<=n;i++){ aim = -1; if(vis[i]==0&&ru[i]==0){ dfs(i, ++tm); if(aim != -1){ while(aim != 0){ flag[aim] = 1; aim = pre[aim]; } } } } for(int i=1;i<=n;i++) if(flag[i]==1) ans++; printf("0 %d\n",ans); } return 0; } /* 10 7 2 v 3 v 4 v 5 v 6 w 7 v 3 v */