BZOJ 3495 [2-SAT]

来源:互联网 发布:法国制造业年度数据 编辑:程序博客网 时间:2024/06/07 00:21

Description

k个国家,n个城市,m条边。要求每个国家有且仅有一个首都,每条边两端的城市至少要有一个首都。判断是否有解, 有解输出“TAK”,无解输出”NIE”。1k,n,m1000000

Solution

经典二元关系 2-SAT 的模型,但是关系数是 O(n 2 ) 的,不
能承受。
对于一个有 y 个城市的国家,新建 2y 个变量,分别表示前
i 个城市和后 i 个城市中是否有首都。
如此一来关系数降至 O(n + m)。
时间复杂度 O(n + m)。
by Claris

#include <cstdio>#include <iostream>using namespace std;const int N = 6010101;inline char get(void) {    static char buf[100000], *S = buf, *T = buf;    if (S == T) {        T = (S = buf) + fread(buf, 1, 100000, stdin);        if (S == T) return EOF;    }    return *S++;}inline void read(int &x) {    static char c; x = 0; int sgn = 0;    for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;    for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';    if (sgn) x = -x;}int k, n, m, Gcnt, x, y, p, Scnt, cnt, dlc, top;int c[N];int S[N];struct edge {    int to, next;    edge(int t = 0, int n = 0):to(t), next(n) {}};edge G[N * 2];int head[N], pre[N], low[N], scc[N];inline void AddEdge(int from, int to) {    G[++Gcnt] = edge(to, head[from]); head[from] = Gcnt;}inline int Min(int a, int b) {    return a < b ? a : b;}void dfs(int u) {    pre[u] = low[u] = ++dlc;    int to; S[++top] = u;    for (int i = head[u]; i; i = G[i].next) {        to = G[i].to;        if (!pre[to]) {            dfs(to); low[u] = Min(low[u], low[to]);        } else if (!scc[to]) {            low[u] = Min(low[u], pre[to]);        }    }    if (low[u] == pre[u]) {        Scnt++; int x;        while (true) {            x = S[top]; top--;            scc[x] = Scnt;            if (x == u) break;        }    }}bool Check(void) {    int lim = cnt << 1 | 1;    for (int i = 1; i <= lim; i++)        if (!pre[i]) dfs(i);    for (int i = 1; i <= cnt; i++)        if (scc[i << 1] == scc[i << 1 | 1]) return false;    return true;}int main(void) {    read(n); read(m); read(k);    for (int i = 0; i < m; i++) {        read(x); read(y);        AddEdge(x << 1, y << 1 | 1);        AddEdge(y << 1, x << 1 | 1);    }    cnt = n;    while (k--) {        read(p);         for (int i = 1; i <= p; i++) {            read(x); y = cnt + i;            if (i != 1) {                AddEdge((y - 1) << 1 | 1, y << 1 | 1);                AddEdge(y << 1, (y - 1) << 1);                AddEdge(x << 1 | 1, (y - 1) << 1);            } else {                AddEdge(x << 1, y << 1);            }            AddEdge(y << 1, x << 1);            AddEdge(x << 1 | 1, y << 1 | 1);            y = cnt + i + p;            if (i != p) {                AddEdge((y + 1) << 1 | 1, y << 1 | 1);                AddEdge(y << 1, (y + 1) << 1);                AddEdge(x << 1 | 1, (y + 1) << 1);            } else {                AddEdge(x << 1, y << 1);            }            AddEdge(y << 1, x << 1);            AddEdge(x << 1 | 1, y << 1 | 1);        }        cnt += p * 2;    }    if (Check()) printf("TAK\n");    else printf("NIE\n");    return 0;}
0 1
原创粉丝点击