HDU 6370 Werewolf 【推理+基环树】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hhhhhhxh/article/details/81516670

题目链接

题意:有n个人玩游戏,每个人会说另一个人是狼人或者村民,已知狼人可能说谎话,村民一定说真话,问最终有几个人一定是狼人,几个人一定是村民。

这里写图片描述
这里写图片描述

参照题解。村民边反向建边,狼人边正向建边。枚举所有的狼人边,如果这条狼人边的起点和终点同属于一个连通块则标记终点所在子树都是狼人。用并查集维护连通块。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;

int T, n, x;
char s[20];
bool ans[maxn], vis[maxn];
int belong[maxn];

struct lEdge { // 狼人边
    int from, to;
    lEdge() {}
    lEdge(int u, int v): from(u), to(v) {}
} ledge[maxn];
int cntlE = 0;

struct Edge { // 村民边
    int from, to, next;
} edge[maxn];
int head[maxn], cntE = 0;

int par[maxn];

int find(int x) {
    if (x == par[x])    return x;
    else    return par[x] = find(par[x]);
}

void join(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y)
        return;
    par[y] = x;
}

bool same(int x, int y) {
    return find(x) == find(y);
}

void init() {
    for (int i = 1; i <= n; i++) {
        par[i] = i;
    }
    memset(ans, false, sizeof(ans));
    memset(head, -1, sizeof(head));
    cntE = 0;
    cntlE = 0;
}

void addedge(int u, int v) {
    edge[cntE].from = u;
    edge[cntE].to = v;
    edge[cntE].next = head[u];
    head[u] = cntE++;
}

void dfs(int rt) {
    vis[rt] = true;
    ans[rt] = true;
    for (int i = head[rt]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        if (!vis[v]) {
            dfs(v);
        }
    }
}

int main() {
#ifdef __APPLE__
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        init();
        for (int i = 1; i <= n; i++) {
            scanf("%d", &x);
            scanf("%s", s);
            if (s[0] == 'w') {
                ledge[cntlE++] = lEdge(i, x);
            }
            else {
                addedge(x, i);
                join(x, i);
            }
        }
        memset(vis, false, sizeof(vis));
        for (int i = 0; i < cntlE; i++) {
            if (same(ledge[i].from, ledge[i].to)
                    && !vis[ledge[i].to]) {
                dfs(ledge[i].to);
            }
        }
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            if (ans[i]) {
                sum++;
            }
        }
        printf("0 %d\n", sum);
    }
} 

猜你喜欢

转载自blog.csdn.net/hhhhhhxh/article/details/81516670