BZOJ1997: [Hnoi2010]Planar
Description
Input
Output
Sample Input
2
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5
6 9
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
1 4 2 5 3 6
5 5
1 2
2 3
3 4
4 5
5 1
1 2 3 4 5
Sample Output
NO
YES
YES
题解Here!
看完题,蒟蒻表示边数怎么这么多?
然后看完题解,发现根据平面图的性质:边数小于等于3n-6。
不符合的直接跳过。
心里一句MMP。。。
然后可以发现,对于哈密尔顿环之外的任意一条边,要么连在环内部,要么连在环外部。
在一定的条件下(可以简单判断),如果两条边同时连在环内部或同时连在环外部,这两条边就一定会相交。
然后这种限制条件可以跑2-SAT。
把第 i 条边拆成 i 和 i' ,i 表示这条边连在内部,i' 表示连在外部。
对于任意两条不在哈密尔顿环上的边 i -> j,i != j,如果他们不能同时连在环内或环外,则:
1. 建边 i -> j',表示 i 在内则 j 必须在外。
2. 建边 i' -> j,表示 i 在外则 j 必须在内。
3. 建边 j -> i',表示 j 在内则 i 必须在外。
4. 建边 j' -> i,表示 j 在外则 i 必须在内。
然后 Tarjan 求一遍强连通分量,如果存在一个 i 和 i' 在同一个强连通分量里,那么原图不是平面图,否则是平面图。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 100010 #define MAXM 210 using namespace std; int n,m,c,d,top,s,num; int cstack[MAXN],head[MAXN],deep[MAXN],low[MAXN],colour[MAXN],path[MAXN],pos[MAXM]; bool vis[MAXN],circle[MAXM][MAXM]; struct Graph{ int next,to; }a[MAXN<<1]; struct Edge{ int x,y; }b[MAXN],g[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void add(int x,int y){ a[c].to=y;a[c].next=head[x];head[x]=c++; a[c].to=x;a[c].next=head[y];head[y]=c++; } void dfs(int x){ deep[x]=low[x]=d++; vis[x]=true; cstack[top++]=x; for(int i=head[x];i;i=a[i].next){ int v=a[i].to; if(!deep[v]){ dfs(v); low[x]=min(low[x],low[v]); } else if(vis[v])low[x]=min(low[x],deep[v]); } if(low[x]>=deep[x]){ s++; do{ colour[cstack[top-1]]=s; vis[cstack[top-1]]=false; }while(cstack[--top]!=x); } } void work(){ if(m>3*n-6){ printf("NO\n"); return; } circle[path[n]][path[1]]=circle[path[1]][path[n]]=true; pos[path[n]]=n; for(int i=1;i<n;i++){ pos[path[i]]=i; circle[path[i]][path[i+1]]=circle[path[i+1]][path[i]]=true; } for(int i=1;i<=m;i++){ if(circle[b[i].x][b[i].y])continue; num++; g[num].x=b[i].x;g[num].y=b[i].y; } m=num; for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++){ int x_one=pos[g[i].x],y_one=pos[g[i].y],x_two=pos[g[j].x],y_two=pos[g[j].y]; if(x_one>y_one)swap(x_one,y_one);if(x_two>y_two)swap(x_two,y_two); if((x_one<x_two&&x_two<y_one&&y_one<y_two)||(x_two<x_one&&x_one<y_two&&y_two<y_one)){ add(i,j+m); add(i+m,j); } } for(int i=1;i<=(m<<1);i++)if(!deep[i])dfs(i); bool flag=true; for(int i=1;i<=m&&flag;i++)if(colour[i]==colour[i+m])flag=false; if(flag)printf("YES\n"); else printf("NO\n"); } void init(){ c=d=top=1; s=num=0; memset(head,0,sizeof(head)); memset(deep,0,sizeof(deep)); memset(low,0,sizeof(low)); memset(colour,0,sizeof(colour)); memset(circle,false,sizeof(circle)); n=read();m=read(); for(int i=1;i<=m;i++){b[i].x=read();b[i].y=read();} for(int i=1;i<=n;i++)path[i]=read(); } int main(){ int t=read(); while(t--){ init(); work(); } return 0; }