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

来源:互联网 发布:let it go 编辑:程序博客网 时间:2024/05/28 22:10

首先,平面图的性质:边数小于等于3n6。不符合的直接跳过。
然后可以发现,对于哈密尔顿环之外的任意一条边,要么连在环内部,要么连在环外部。在一定的条件下(可以简单判断),如果两条边同时连在环内部或同时连在环外部,这两条边就一定会相交,这样的限制条件符合2-SAT的模型。
把第i条边拆成iii表示这条边连在内部,i表示连在外部。
对于任意两条不在哈密尔顿环上的边i,j,ij,如果他们不能同时连在环内或环外,则:
1、建边<i,j>,表示i在内则j必须在外。
2、建边<i,j>,表示i在外则j必须在内。
3、建边<j,i>,表示j在内则i必须在外。
4、建边<j,i>,表示j在外则i必须在内。
然后求一遍强连通分量,如果存在一个ii在同一个强连通分量里,那么原图不是平面图,否则是平面图。
代码:

#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[N], eY[N], Cir[V], ecnt, nxt[M], adj[N], go[M], dfn[N], low[N],top, times, stk[N], bel[N], sum, rev[V], Ex[N], Ey[N];bool cir[V][V], ins[N];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[n]; 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;}
原创粉丝点击