只要你跑的够快,锅就追不上你

0%

「HNOI 2010」Planar(Tarjan)

题目大意

「HNOI 2010」Planar(BZOJ 1997)

给定一个 $n$ 个结点 $m$ 条边的无向图,保证它有哈密尔顿回路。给定它的一个哈密尔顿回路,问它是不是平面图。

数据范围:$T \le 100, n \le 200, m \le 10^4$。

思路分析

把哈密尔顿回路看作是一个环,其他边看作是环上的一条弦。对于每一条弦,我们要么把它放在环的外面,要么把它放在里面。如果两条弦不相交,那么随便放;否则它们不能在圆的同一侧。于是使用 2 - SAT 来判断是否有解即可。

这样的复杂度还不够优秀,我们考虑优化。发现平面图满足 $m \le 3n - 6$,所以我们加入剪枝即可把复杂度优化到 $O(Tn^2)$。注意 2 - SAT 上表示两个变量取值不相同需要联结四条有向边,而不是一条或两条。

代码实现

1
#include <cstdio>
2
#include <vector>
3
#include <algorithm>
4
using namespace std;
5
6
const int maxn = 1e4;
7
int T, n, m, a[maxn + 3], k, u[maxn + 3], v[maxn + 3], rnk[maxn + 3];
8
int tm, dfn[maxn + 3], low[maxn + 3], top, st[maxn + 3], cnt, bel[maxn + 3];
9
bool in[maxn + 3];
10
vector<int> G[maxn + 3];
11
12
void add(int u, int v) {
13
	G[u].push_back(v);
14
}
15
16
void tarjan(int u) {
17
	dfn[u] = low[u] = ++tm;
18
	st[++top] = u, in[u] = true;
19
	for (int i = 0, v; i < G[u].size(); i++) {
20
		v = G[u][i];
21
		if (!dfn[v]) {
22
			tarjan(v);
23
			low[u] = min(low[u], low[v]);
24
		} else if (in[v]) {
25
			low[u] = min(low[u], dfn[v]);
26
		}
27
	}
28
	if (low[u] == dfn[u]) {
29
		++cnt;
30
		do {
31
			bel[st[top]] = cnt;
32
			in[st[top]] = false;
33
		} while (st[top--] != u);
34
	}
35
}
36
37
int main() {
38
	scanf("%d", &T);
39
	while (T--) {
40
		for (int i = 1; i <= k * 2; i++) {
41
			vector<int> t;
42
			swap(G[i], t);
43
			dfn[i] = 0;
44
		}
45
		k = 0;
46
		scanf("%d %d", &n, &m);
47
		for (int i = 1; i <= m; i++) {
48
			scanf("%d %d", &u[i], &v[i]);
49
		}
50
		for (int i = 1; i <= n; i++) {
51
			scanf("%d", &a[i]);
52
			rnk[a[i]] = i;
53
		}
54
		if (m > 3 * n - 6) {
55
			puts("NO");
56
			continue;
57
		}
58
		for (int i = 1; i <= m; i++) {
59
			int x = rnk[u[i]], y = rnk[v[i]];
60
			if (x > y) {
61
				swap(x, y);
62
			}
63
			if ((x == 1 && y == n) || x == y - 1) {
64
				continue;
65
			}
66
			u[++k] = x, v[k] = y;
67
		}
68
		for (int i = 1; i <= k; i++) {
69
			for (int j = i + 1; j <= k; j++) {
70
				if (u[i] >= u[j] && u[i] <= v[j] && v[i] >= u[j] && v[i] <= v[j]) {
71
					continue;
72
				}
73
				if ((u[i] <= u[j] || u[i] >= v[j]) && (v[i] <= u[j] || v[i] >= v[j])) {
74
					continue;
75
				}
76
				add(i, j + k);
77
				add(j, i + k);
78
				add(i + k, j);
79
				add(j + k, i);
80
			}
81
		}
82
		tm = 0, cnt = 0;
83
		for (int i = 1; i <= k * 2; i++) {
84
			if (!dfn[i]) {
85
				tarjan(i);
86
			}
87
		}
88
		bool flag = true;
89
		for (int i = 1; i <= k; i++) {
90
			if (bel[i] == bel[i + k]) {
91
				flag = false;
92
				break;
93
			}
94
		}
95
		puts(flag ? "YES" : "NO");
96
	}
97
	return 0;
98
}