Loading

P5782 [POI2001] 和平委员会

题目

image

思路

因为每个党只有 2 个代表,所以这个题目很好做。

考虑使用 2-SAT,如果这个党的 \(x\) 厌恶另外一个党的 \(y\),那么如果 \(x\) 存在,那么 \(y\) 不能参加,而一个党必须有一个人,所以只能由 \(y\) 的同伙出席,反之亦然。

这已具备 2-SAT 题目特征,连边即可。

无解的情况为:一个党的两个人在一个强连通分量里。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2000010;

struct edge {
    int to, next;
} e[N];

int head[N], idx = 1;

void add(int u, int v) {
    idx++, e[idx].to = v, e[idx].next = head[u], head[u] = idx;
}

int n, m;
int dfn[N], low[N], cnt;
int stk[N], top;
bool instk[N];
int scc[N], tot;

void tarjan(int u) {
    stk[++top] = u, instk[u] = 1;
    dfn[u] = low[u] = ++cnt;
    for (int i = head[u]; i; i = e[i].next) {
        int to = e[i].to;
        if (!dfn[to]) {
            tarjan(to);
            low[u] = min(low[u], low[to]);
        }
        else if (instk[to]) low[u] = min(low[u], dfn[to]);
    }

    if (dfn[u] == low[u]) {
        tot++;
        while (stk[top] != u) {
            int t = stk[top];
            top--;
            instk[t] = 0;
            scc[t] = tot;
        }
        top--;
        instk[u] = 0;
        scc[u] = tot;
    }
}

int turn(int x) {
    if (x & 1) return x + 1;
    else return x - 1;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int p1, p2;
        cin >> p1 >> p2;
        add(p1, turn(p2));
        add(p2, turn(p1));
    }

    for (int i = 1; i <= 2 * n; i++) if (!dfn[i]) tarjan(i);

    for (int i = 1; i <= 2 * n; i += 2) {
        if (scc[i] == scc[i + 1]) {
            cout << "NIE\n";
            return 0;
        }
    }
    for (int i = 1; i <= 2 * n; i += 2) {
        if (scc[i + 1] < scc[i]) cout << i + 1 << '\n';
        else cout << i << '\n';
    }
    return 0;
}
posted @ 2024-08-29 00:08  SunnyYuan  阅读(2)  评论(0编辑  收藏  举报