P6378 [PA 2010] Riddle
nnn 个点 mmm 条边的无向图被分成 kkk 个部分。每个部分包含一些点。
请选择一些关键点,使得每个部分恰有一个关键点,且每条边至少有一个端点是关键点。判断是否有解。
连边是容易的。
因为每个部分都正好有 111 个点,所以设点集为 a1,a2,...,an{a_1,a_2,...,a_n}a1,a2,...,an,则连 ∀1≤i,j(i,j are not the same)≤n,ai→−aj\forall 1 \le i,j(i , j \ \text{are not the same}) \le n,a_i \to -a_j∀1≤i,j(i,j are not the same)≤n,ai→−aj 的边。
对于每一条边 (x,y)(x,y)(x,y),有 −x→y-x \to y−x→y、−y→x-y \to x−y→x。
然后就可以幸福愉快地跑 2-SAT。复杂度达到了残酷的 O(n2)O(n^2)O(n2),无法通过。
因为只有一个部分中的点连边花销较大,边的数量实际上还是 nnn 的量级。所以考虑优化一下同一个部分中的点的连边。
这样是我们最开始的连边方式。
但是这样还是太慢了。
这个时候不能删边也不能删点,考虑类似一开始 2-SAT 的方式加点。
我们考虑再建 2×n2 \times n2×n 个虚点。
对于上面的点,每一个点连向自己的虚点。
对于下面的点,每一个自己的虚点连向自己。
感觉还更乱了。
然后再对于上面的点,每一条出边的起点再设为它的虚点。
然后再对于下面的点,每一条入边的终点再设为它的虚点。
这样就可以开始幸福愉快地删边了!
经过尝试发现这样是合法的,也是可以的。
这样,边数又变成了 O(n)O(n)O(n)。
点数注意开 4 倍空间!如果你采用的是链式前向星,也要注意空间(还要开 6 倍)。
#include <bits/stdc++.h>
using namespace std;
const int N = 4000010;
int n, m, k;
vector<int> v[N], p;
int dfn[N], low[N], ind;
stack<int> stk;
int color[N], s_cnt;
void tarjan(int u) {
dfn[u] = low[u] = ++ind;
stk.push(u);
for (auto i : v[u]) {
if (!dfn[i])
tarjan(i), low[u] = min(low[u], low[i]);
else if (!color[i])
low[u] = min(low[u], dfn[i]);
}
if (low[u] == dfn[u]) {
int x;
s_cnt++;
do {
x = stk.top();
stk.pop();
color[x] = s_cnt;
} while (x != u);
}
}//tarjan
int main() {
cin >> n >> m >> k;
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
v[x + n].push_back(y);
v[y + n].push_back(x);
}
for (int i = 1; i <= k; i++) {
int x;
cin >> x;
p.clear();
while (x--) {
int a;
cin >> a;
p.push_back(a);
}
for (auto a : p)
v[a].push_back(a + 2 * n), v[a + 3 * n].push_back(a + n);
for (int i = 0; i < (int)p.size(); i++) {
if (i != 0)
v[p[i]].push_back(p[i - 1] + 3 * n), v[p[i] + 3 * n].push_back(p[i - 1] + 3 * n);
if (i != p.size() - 1)
v[p[i] + 2 * n].push_back(p[i + 1] + n), v[p[i] + 2 * n].push_back(p[i + 1] + 2 * n);
}//连边,上面讲过。一共有 6 种边,一种都不要忘记
}
for (int i = 1; i <= 4 * n; i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
if (color[i] == color[i + n]) {//直接判断无解即可
cout << "NIE\n";
return 0;
}
cout << "TAK\n";
return 0;
}