[HNOI2010]平面圖判定
阿新 • • 發佈:2018-11-02
題意
思考
如果單獨的平面圖判定肯定是很麻煩的,但題目給了一個條件,此平面圖存在哈密頓迴路,我們將哈密頓迴路畫成一個圓,那麼原圖的邊(除去哈密頓迴路上的邊)可以看作是該圓的弦,考慮圓中兩條相交的弦 \((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