Address
Solution
- 很容易想到是 2−SAT 2 − S A T 判断是否有解。
- 满足每条边至少有一个端点是首都很好处理,对于每一条边
(x,y)
(
x
,
y
)
:
- 不选 x x 就一定要选 。
- 不选 y y 就一定要选 。
- 对于每个郡
{a1,a2,...,aw}
{
a
1
,
a
2
,
.
.
.
,
a
w
}
只能选一个首都,记点
bi
b
i
表示该郡前
i
i
个点是否被选,则:
- 选了 就一定要选 bi b i 。
- 没选 bi b i 就一定不选 ai a i 。
- 选了 bi−1 b i − 1 就一定要选 bi b i 。
- 没选 bi b i 就一定不选 bi−1 b i − 1 。
- 选了 ai a i 就一定不选 bi−1 b i − 1 。
- 选了 bi−1 b i − 1 就一定不选 ai a i 。
- 按照上述要求建边即可。
Code
#include <cstdio> #include <iostream> #include <cstring> #include <cctype> #include <algorithm> using namespace std; inline int get() { char ch; int res = 0; bool flag = false; while (ch = getchar(), !isdigit(ch) && ch != '-'); (ch == '-' ? flag = true : res = ch ^ 48); while (ch = getchar(), isdigit(ch)) res = res * 10 + ch - 48; return flag ? -res : res; } const int N = 4e6 + 5, M = 1e7 + 5; struct Edge { int to; Edge *nxt; }p[M], *lst[N], *P = p; int dfn[N], low[N], stk[N], col[N]; bool inv[N]; int n, m, K, tis, C, top, a[N], b[N]; inline void Link(int x, int y) { (++P)->nxt = lst[x]; lst[x] = P; P->to = y; } inline void CkMin(int &x, int y) {if (x > y) x = y;} inline void Tarjan(int x) { dfn[x] = low[x] = ++tis; int y; stk[++top] = x; inv[x] = true; for (Edge *e = lst[x]; e; e = e->nxt) if (!dfn[y = e->to]) Tarjan(y), CkMin(low[x], low[y]); else if (inv[y]) CkMin(low[x], dfn[y]); if (dfn[x] == low[x]) { inv[x] = false; col[x] = ++C; while (y = stk[top--], y != x) inv[y] = false, col[y] = C; } } int main() { n = get(); m = get(); K = get(); int x, y, w; while (m--) { x = get(); y = get(); Link(x + n, y); Link(y + n, x); } for (int i = 1; i <= n; ++i) Link(i, i + n + n), Link(i + n + n + n, i + n); while (K--) { w = get(); for (int i = 1; i <= w; ++i) { a[i] = get(); b[i] = a[i] + n + n; } for (int i = 2; i <= w; ++i) { Link(b[i - 1], b[i]); Link(b[i] + n, b[i - 1] + n); Link(a[i], b[i - 1] + n); Link(b[i - 1], a[i] + n); } } for (int i = 1, im = n << 2; i <= im; ++i) if (!dfn[i]) Tarjan(i); bool flag = false; for (int i = 1; i <= n; ++i) if (col[i] == col[i + n]) { flag = true; break; } for (int i = 1; i <= n; ++i) if (col[i + n + n] == col[i + n + n + n]) { flag = true; break; } puts(flag ? "NIE" : "TAK"); }