1. 程式人生 > >[HNOI2010]平面圖判定

[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