【題解】HNOI-2010 Planar

Problem

bzoj
洛谷

題意:給定一張完全圖和圖中的一條哈密頓迴路,問是否爲平面圖

Solution

看到這題中有一條哈密頓迴路,如果這個圖是平面圖,那麼這條哈密頓迴路在平面上就是一個切割平面的圈

明顯想到每一條非哈密頓迴路上的邊不會和這個圈相交,則一定在這個圈的外部或內部

發現如果將兩條邊放在圈的同一側必定相交,那麼就必須把它倆分開(一條在裏面一條在外面),那麼對每兩條邊來說有可能有上述限制條件,最後看所有條件是否會衝突

判斷衝突的方法比較多,一般根據衝突建圖,然後tarjan、變種匈牙利、並查集隨便搞,不建圖也能用搜索水過

發現這樣的話,枚舉每兩條邊考慮限制條件是O(m2) 的,然而m10000,T100 使得我們不得不優化這個複雜度

數學知識:一個有n 個點的平面圖上最多有n36 條邊(在數學組小藍皮上有很多比較有用的平面圖知識)

據此可以將邊數大於n36 的情況預判掉,剩下的情況中邊數與點數是同一個量級200

蒟蒻用的是並查集

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rg register
#define cl(x) memset(x,0,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)>0?(x):(-(x)))

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=205,M=10500;
int dad[M],d[M],l[M],r[M],cannot[M];
int n,m;

inline int father(int x){return dad[x]?dad[x]=father(dad[x]):x;}

int main(){
    int T;read(T);while(T--){
        read(n);read(m);
        if(3*n+6<m){
            for(rg int i=1,x;i<=m;++i)read(x),read(x);
            for(rg int i=1,x;i<=n;++i)read(x);
            puts("NO");continue;
        }cl(dad);cl(cannot);
        for(rg int i=1;i<=m;++i)read(l[i]),read(r[i]);
        for(rg int i=1,x;i<=n;++i)d[read(x)]=i;
        for(rg int i=1;i<=m;++i){
            l[i]=d[l[i]],r[i]=d[r[i]];
            if(l[i]>r[i])swap(l[i],r[i]);
            if(l[i]+1==r[i]||(l[i]==1&&r[i]==n))cannot[i]=1;
        }
        int p1,p2;
        for(rg int i=1;i<=m;++i)if(!cannot[i])
        for(rg int j=i+1;j<=m;++j)if(!cannot[j])
            if( (l[i]<l[j] && l[j]<r[i] && r[i]<r[j]) || (l[j]<l[i] && l[i]<r[j] && r[j]<r[i]) )
            if( l[i]!=l[j] && r[i]!=r[j] && l[i]!=r[j] && r[i]!=l[j] ){
                if(father(i)==father(j))goto end;
                if((p1=father(i))!=(p2=father(j+m))) dad[p1]=p2;
                if((p1=father(j))!=(p2=father(i+m))) dad[p1]=p2;
            }
        for(rg int i=1;i<=m;++i)if(father(i)==father(i+m))goto end;
        puts("YES");continue;
        end : puts("NO");
    }
}
發佈了100 篇原創文章 · 獲贊 49 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章