BZOJ1997 : [HNOI2010] Planar (2-SAT)

题意

给你一个有 \(n\) 个点的图 里面有 \(m\) 条边

并给你图上一条哈密顿回路 然后让你判断它是否为平面图

平面图就是存在一种情况 使得边两两不相交 数据共 \(T\)

\[(T \le 100 , 3 \le n \le 200, m \le 10000) \]

题解

这题是我见过最不裸的 \(2-SAT\) 了 根本不会啊

判断平面图 有一些鬼畜的算法可以做 但根本不会啊

这题比较特殊 给了一条哈密顿回路 那么我们可以利用这个性质

不难发现 如果两条边会相交 那么他们不能同时存在 在 哈密顿圈 内 或者 外面

这样 我们对于原图中每条边就变成 \(2-SAT\) 上的点然后去判断就行了

至于判边相交 考虑如下一种情况

pic

我们将这个环重新标号 标为 \(1 \to 6\)

然后如果两条边 (设为 \(u_i \to v_i\)\(u_j \to v_j\) 强制 \(u_i < u_j , u_i < v_i , u_j < v_j\) ) 会相交 那么我们就有一个不等式

\[u_i < u_j < v_i < v_j \]

所有相交情况都可以这样转化

但数据组数多 边的范围原超过点的范围 可能会TLE

所以我们就可以用个性质进行一些优化

平面图上 边数 \(E\) 和 点数 \(V\) 满足 \(E \le V * 3 - 6\)

这个一开始直接判就行了qwq

代码

有一些鬼畜的地方 就是点和边的范围 以及 他们一开始清空的范围

/**************************************************************
    Problem: 1997
    User: zjp_shadow
    Language: C++
    Result: Accepted
    Time:180 ms
    Memory:10440 kb
****************************************************************/
 
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
 
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
 
inline int read() {
    int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
    for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
    return x * fh;
}
 
void File() {
#ifdef zjp_shadow
    freopen ("1997.in", "r", stdin);
    freopen ("1997.out", "w", stdout);
#endif
}
 
const int N = 110000 << 1, M = 100100 << 1;
 
struct Two_SAT {
#define Travel(i, u, v) for(int i = Head[u], v = to[i]; i; i = Next[i], v = to[i])
    int Head[N], Next[M], to[M], e, n;
 
    void add_edge(int u, int v) { to[++ e] = v; Next[e] = Head[u]; Head[u] = e; }
 
    void Add(int x, int xv, int y, int yv) {
        x = x << 1 | xv;
        y = y << 1 | yv;
        add_edge(x, y);
        add_edge(y ^ 1, x ^ 1);
    }
 
    void Init(int n) {
        this -> n = n; e = 0; 
        For (i, 1, n * 2 + 10) Head[i] = 0;
    }
 
    int sccno[N], scc_cnt;
    int clk, dfn[N], lowlink[N];
    int sta[N], top;
    void Tarjan(int u) {
        lowlink[u] = dfn[u] = ++ clk; sta[++ top] = u;
        Travel(i, u, v)
            if (!dfn[v]) Tarjan(v), chkmin(lowlink[u], lowlink[v]);
            else if (!sccno[v]) chkmin(lowlink[u], dfn[v]);
        if (lowlink[u] == dfn[u]) {
            ++ scc_cnt;
            for (;;) {
                int x = sta[top --];
                sccno[x] = scc_cnt;
                if (x == u) break;
            }
        }
    }
 
    bool Solve() {
        For (i, 1, n * 2 + 10)
            dfn[i] = sccno[i] = lowlink[i] = 0;
        scc_cnt = clk = top = 0;
        For (i, 1, n * 2 + 1)
            if (!dfn[i]) Tarjan(i);
        For (i, 1, n)
            if (sccno[i << 1] == sccno[i << 1 | 1]) return false;
        return true;
    }
} T;
 
struct Edge{
    int u, v;
    inline bool operator < (const Edge &rhs) const {
        return (u ^ rhs.u) ? u < rhs.u : v < rhs.v;
    }
} lt[M];
 
int ver[N], num[N];
 
int main () {
    File();
    int cases = read();
    while (cases --) {
        int n = read(), m = read();
        For (i, 1, m) {
            lt[i].u = read();
            lt[i].v = read();
        }
        For (i, 1, n) {
            ver[i] = read();
            num[ver[i]] = i;
        }
        if (m > 3 * n - 6) { puts("NO"); continue; }
        For (i, 1, m) {
            lt[i].u = num[lt[i].u];
            lt[i].v = num[lt[i].v];
            if (lt[i].u > lt[i].v) swap(lt[i].u, lt[i].v);
        }
        sort(lt + 1, lt + 1 + m);
        T.Init(n);
        For (i, 1, m) For (j, i + 1, m) {
            if (lt[i].u == lt[i].v - 1 || (lt[i].u == 1 && lt[i].v == n)) continue ;
            if (lt[i].u < lt[j].u && lt[j].u < lt[i].v && lt[i].v < lt[j].v) {
                T.Add(i, 1, j, 0);
                T.Add(i, 0, j, 1);
            }
        }
        puts(T.Solve() ? "YES" : "NO");
    }
    return 0;
}
posted @ 2018-04-05 11:26  zjp_shadow  阅读(166)  评论(5编辑  收藏  举报