条件转化,2-sat BZOJ 1997
http://www.lydsy.com/JudgeOnline/problem.php?id=1997
1997: [Hnoi2010]Planar
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1810 Solved: 684
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
2
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5
Sample Output
NO
YES
YES
思路:(from 出题人):http://www.cnblogs.com/jinkun113/p/4894499.html
如果只考虑简单的平面图判定,这个问题是非常不好做的。
但是题目中有一个条件——这张图存在一条哈密顿回路。
我们把哈密顿回路在平面上画成一个圆。仔细观察一下。
每条边如果画在圆内都是一条弦,那如果弦在圆内相交怎么办?把另一条弦翻出去。能不能两条弦都翻出去呢?不能,因为如果两条边在圆内相交,那么它们在圆外也会相交。那我们是不是就相当于就多了一个条件:这两条边不能同时在一个域内。
所以,这张图中总共只有两个域,圆内和圆外。那么我们是不是就转化了模型:有若干个点和若干条边,你要给每个点黑白染色,使得每条边的两个端点颜色不同。直接DFS就可以了。还有个问题,边数是10^4,暴力连边会超时,但是平面图有一个定理:m<=3*n+6,那这个定理来剪枝就行了。
然后我们只要对输入的哈密顿环进行标号,然后这样就是一个圈,假定刚开始都是在圈内,然后我们只需要判断是否在圈内就行了。
好像我的代码因为用了map和edges这些东西,所以跑的速度比别人慢一个log= =,别人都是200ms左右,我是2000ms,人生第一次体验到了map所带来的绝望
#include <bits/stdc++.h> using namespace std; #pragma comment(linker,"/STACK:102400000,102400000") #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha\n") const int maxn = 1e5 + 5; struct TwoSat{ int n, c, s[maxn * 2]; bool mark[maxn << 1]; vector<int> G[maxn << 1]; void init(int n){ this->n = n; for (int i = 0; i < 2 * n; i++) G[i].clear(); memset(mark, false, sizeof(mark)); } void add_edge(int x, int xval, int y, int yval){ x = x * 2 + xval, y = y * 2 + yval; G[x ^ 1].pb(y), G[y ^ 1].pb(x); } void display(){ for (int i = 0; i < 2 * n; i++){ printf("from = %d\n", i); for (int j = 0; j < G[i].size(); j++){ printf("%d ", G[i][j]); } cout << endl; } } bool dfs(int x){ if (mark[x ^ 1]) return false; if (mark[x]) return true; mark[x] = true; s[c++] = x; for (int i = 0; i < G[x].size(); i++){ if (!dfs(G[x][i])) return false; } return true; } bool solve(){ for (int i = 0; i < n * 2; i += 2){ if (!mark[i] && !mark[i + 1]){ c = 0; if (!dfs(i)){ while (c) mark[s[--c]] = false; if (!dfs(i + 1)) return false; } } } return true; } }; TwoSat tar; int n, m; map<int, int> id; map<pair<int, int>, int> Point; vector<pair<int, int> > edges; bool test(int u1, int v1, int u2, int v2){ if (u2 > u1 && u2 < v1 && v2 > v1) return true; if (u1 > u2 && u1 < v2 && v1 > v2) return true; return false; } int main(){ int T; cin >> T; while (T--){ scanf("%d%d", &n, &m); id.clear(); edges.clear(); for (int i = 0; i < m; i++){ int u, v; scanf("%d%d", &u, &v); if (u > v) swap(u, v); edges.push_back(mk(u, v)); } for (int i = 1; i <= n; i++){ int u; scanf("%d", &u); id[u] = i; } if (m >= n * 3 + 6){ puts("NO"); continue; } tar.init(m); for (int i = 0; i < m; i++){ int x1 = edges[i].fi, y1 = edges[i].se; x1 = id[x1], y1 = id[y1]; if (x1 > y1) swap(x1, y1); for (int j = i + 1; j < m; j++){ int x2 = edges[j].fi, y2 = edges[j].se; x2 = id[x2], y2 = id[y2]; if (x2 > y2) swap(x2, y2); //if (x1 == x2 || x1 == y2 || y1 == x2 || y1 == y2) continue; if (test(x1, y1, x2, y2)){///假定刚开始都是在里面的 tar.add_edge(i, 0, j, 0); tar.add_edge(i, 1, j, 1); } } } //tar.display(); if (tar.solve()) puts("YES"); else puts("NO"); } return 0; }