您的位置:首页 > 其它

[BZOJ1997][HNOI2010]Planar(2-SAT)

2017-12-02 11:52 423 查看
首先,平面图的性质:边数小于等于3n−6。不符合的直接跳过。

然后可以发现,对于哈密尔顿环之外的任意一条边,要么连在环内部,要么连在环外部。在一定的条件下(可以简单判断),如果两条边同时连在环内部或同时连在环外部,这两条边就一定会相交,这样的限制条件符合2-SAT的模型。

把第i条边拆成i和i′,i表示这条边连在内部,i′表示连在外部。

对于任意两条不在哈密尔顿环上的边i,j,i≠j,如果他们不能同时连在环内或环外,则:

1、建边<i,j′>,表示i在内则j必须在外。

2、建边<i′,j>,表示i在外则j必须在内。

3、建边<j,i′>,表示j在内则i必须在外。

4、建边<j′,i>,表示j在外则i必须在内。

然后求一遍强连通分量,如果存在一个i和i′在同一个强连通分量里,那么原图不是平面图,否则是平面图。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int V = 205, N = 3e4 + 5, M = 2e6 + 5;
int n, m, eX
, eY
, Cir[V], ecnt, nxt[M], adj
, go[M], dfn
, low
,
top, times, stk
, bel
, sum, rev[V], Ex
, Ey
;
bool cir[V][V], ins
;
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}
void Tarjan(int u) {
dfn[u] = low[u] = ++times;
stk[++top] = u; ins[u] = 1;
for (int e = adj[u], v; e; e = nxt[e])
if (!dfn[v = go[e]]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (ins[v]) low[u] = min(low[u], dfn[v]);
if (dfn[u] == low[u]) {
int v; bel[u] = ++sum; ins[u] = 0;
while (v = stk[top--], v != u) bel[v] = sum, ins[v] = 0;
}
}
bool check() {
int i; for (i = 1; i <= (m << 1); i++)
if (!dfn[i]) Tarjan(i);
for (i = 1; i <= m; i++)
if (bel[i] == bel[i + m]) return 0;
return 1;
}
void work() {
ecnt = times = sum = 0; memset(adj, 0, sizeof(adj));
memset(dfn, 0, sizeof(dfn)); memset(bel, 0, sizeof(bel));
memset(low, 0, sizeof(low)); memset(cir, 0, sizeof(cir));
int i, j, u, v, x, y, tot = 0; n = read(); m = read();
for (i = 1; i <= m; i++) {
eX[i] = read(); eY[i] = read();
if (eX[i] > eY[i]) swap(eX[i], eY[i]);
}
for (i = 1; i <= n; i++) {
rev[Cir[i] = read()] = i;
if (i > 1) {
x = Cir[i - 1]; y = Cir[i];
if (x < y) cir[x][y] = 1;
else cir[y][x] = 1;
}
}
if (m > 3 * n - 6) return (void) (printf("NO\n"));
x = Cir
; y = Cir[1]; ((x < y) ? cir[x][y] : cir[y][x]) = 1;
for (i = 1; i <= m; i++) {
if (cir[eX[i]][eY[i]]) continue;
Ex[++tot] = eX[i]; Ey[tot] = eY[i];
}
m = tot; for (i = 1; i < m; i++) for (j = i + 1; j <= m; j++) {
u = rev[Ex[i]], v = rev[Ey[i]], x = rev[Ex[j]], y = rev[Ey[j]];
if (u > v) swap(u, v); if (x > y) swap(x, y);
if ((u < x && v > x && v < y) || (u > x && u < y && v > y)) {
add_edge(i, j + m); add_edge(i + m, j);
add_edge(j, i + m); add_edge(j + m, i);
}
}
printf(check() ? "YES\n" : "NO\n");
}
int main() {
int T = read();
while (T--) work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: