[HNOI2010]平面图判定

题意

Here

思考

如果单独的平面图判定肯定是很麻烦的,但题目给了一个条件,此平面图存在哈密顿回路,我们将哈密顿回路画成一个圆,那么原图的边(除去哈密顿回路上的边)可以看作是该圆的弦,考虑圆中两条相交的弦 \((u_1, v_1),(u_2, v_2)(u_1,v_1),(u_2,v_2)\) ,由于是平面图,我们可以将其中的一条翻到圆外去(但两条弦不能同时翻到圆外去,原因是如果他们在圆内相交,那么在圆外也会相交,可以画图模拟一下),我们考虑将弦视为点,把相交的弦连边,这样,平面图的判定就转为了新图的二分图判定~

要注意的一点:按照题中所给的m的范围是过不去的,但这其实是个假数据范围,平面图有一条性质是 \(m \leq 3n-6\),有兴趣的同学可以去了解一下证明

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x * f;
}
const int M = 10010;
struct node{
    int nxt, to;
}edge[700 * 700 * 2];
int head[M], num, col[M];
void build(int from, int to){
    edge[++num].nxt = head[from];
    edge[num].to = to;
    head[from] = num;
}
bool dfs(int u, int color){
    col[u] = color;
    for(int i=head[u]; i; i=edge[i].nxt){
        int v = edge[i].to;
        if(col[v] == color) return 0;
        if(col[v] == 0 && !dfs(v, -color)) return 0;
    }
    return 1;
}
bool check(int u1, int v1, int u2, int v2){
    return (u1 < u2 && u2 < v1 && v1 < v2) || (u2 < u1 && u1 < v2 && v2 < v1);
}
int t, n, m;
int from[M], to[M], G[M];
void clearx(){
    memset(head, 0, sizeof(head)); num = 0;
    memset(col, 0, sizeof(col));
    memset(G, 0, sizeof(G));
}
int main(){
    t = read();
    while(t --){
        n = read(), m = read(); int flag = 0;
        clearx();
        for(int i=1; i<=m; i++){
            from[i] = read(); to[i] = read();
        }
        for(int i=1; i<=n; i++) G[read()] = i;
        if(m > 3 * n - 6){
            puts("NO"); continue;
        }
        for(int i=1; i<=m-1; i++){
            for(int j=i+1; j<=m; j++){
                int u1 = G[from[i]], v1 = G[to[i]], u2 = G[from[j]], v2 = G[to[j]];
                if(u1 > v1) swap(u1, v1); if(u2 > v2) swap(u2, v2);
                if( check(u1, v1, u2, v2) ) build(i, j), build(j, i);
            }
        }
        for(int i=1; i<=m; i++){
            if(col[i] == 0){
                if(!dfs(i, 1)){
                    flag = 1;
                    break;
                }
            }
        }
        if(!flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

总结

题目要分析清楚,某些题目可能会有坑(比如这题m的虚假范围)。有时候能把题目转换成较简单的问题(将本题平面图判定转为了二分图判定)。本题还有其他解法:并查集/2-SAT

posted @ 2018-11-02 19:29  alecli  阅读(331)  评论(0编辑  收藏  举报