洛谷P3209 [HNOI2010]PLANAR(2-SAT)
题目描述
若能将无向图G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称G是平面图。判定一个图是否为平面图的问题是图论中的一个重要问题。现在假设你要判定的是一类特殊的图,图中存在一个包含所有顶点的环,即存在哈密顿回路。
输入输出格式
输入格式:
输入文件的第一行是一个正整数T,表示数据组数(每组数据描述一个需要判定的图)。接下来从输入文件第二行开始有T组数据,每组数据的第一行是用空格隔开的两个正整数N和M,分别表示对应图的顶点数和边数。紧接着的M行,每行是用空格隔开的两个正整数u和v(1<=u,v<=n),表示对应图的一条边(u,v),输入的数据保证所有边仅出现一次。每组数据的最后一行是用空格隔开的N个正整数,从左到右表示对应图中的一个哈密顿回路:V1,V2,…,VN,即对任意i≠j有Vi≠Vj且对任意1<=i<=n-1有(Vi,Vi-1) ∈E及(V1,Vn) ∈E。输入的数据保证100%的数据满足T<=100,3<=N<=200,M<=10000。
输出格式:
包含T行,若输入文件的第i组数据所对应图是平面图,则在第i行输出YES,否则在第i行输出NO,注意均为大写字母
输入输出样例
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
NO YES
说明
感谢@hibiki 对题目进行修正
如果你会做POJ3207的话,那么这道题就是道大水题
不过平面图有一个性质
边数$<=$点数$*3-6$
因此可以通过这个性质把数据规模降至$O(n)$
设$i$表示边$i$在圆内,$i'$表示$i$在圆外
若$(i,j)$在圆内相交,那么它们在圆外也一定相交
如果边$i,j$在圆内相交
那么就从$i$连向$j'$(i内j外),从$j'$连向$i$(i内j外),从$j$连向$i'$(j内i外),从$i'$连向$j$(j内i外)
写错了一个字母调了半个小时
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #include<vector> #include<queue> #include<iostream> #define Pair pair<int,int> #define F first #define S second using namespace std; const int MAXN=1e6+10; //#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++) char buf[1<<20],*p1=buf,*p2=buf; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } struct node { int u,v,nxt; }edge[MAXN]; int head[MAXN],num=1; inline void AddEdge(int x,int y) { edge[num].u=x; edge[num].v=y; edge[num].nxt=head[x]; head[x]=num++; } int happen[MAXN]; int dfn[MAXN],low[MAXN],tot,color[MAXN],colornum=0,vis[MAXN]; stack<int>s; int N,M; Pair P[MAXN]; void tarjan(int now) { dfn[now]=low[now]=++tot; s.push(now); vis[now]=1; for(int i=head[now];i!=-1;i=edge[i].nxt) { if(!dfn[edge[i].v]) tarjan(edge[i].v),low[now]=min(low[now],low[edge[i].v]); else if(vis[edge[i].v]) low[now]=min(low[now],dfn[edge[i].v]); } if(dfn[now]==low[now]) { int h;colornum++; do { h=s.top();s.pop(); vis[h]=0; color[h]=colornum; }while(h!=now); } } void pre() { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(head,-1,sizeof(head)); memset(color,0,sizeof(color)); memset(happen,0,sizeof(happen)); memset(vis,0,sizeof(vis)); num=1; } int main() { #ifdef WIN32 freopen("a.in","r",stdin); freopen("a.out","w",stdout); #else #endif int QWQ=read(); while(QWQ--) { pre(); N=read();M=read(); for(int i=1;i<=M;i++) P[i].F=read(),P[i].S=read(); for(int i=1;i<=N;i++) { int p=read(); happen[p]=i; } if(M>3*N-6){printf("NO\n"); continue;} for(int i=1;i<=M;i++) { P[i].F=happen[P[i].F]; P[i].S=happen[P[i].S]; if(P[i].F>P[i].S) swap(P[i].F,P[i].S); } for(int i=1;i<=M;i++) for(int j=i+1;j<=M;j++) if((P[i].S>P[j].F&&P[i].F<P[j].F&&P[i].S<P[j].S) ||(P[i].F>P[j].F&&P[i].S>P[j].S&&P[i].F<P[j].S)) AddEdge(i,j+M), AddEdge(j+M,i), AddEdge(j,i+M), AddEdge(i+M,j); for(int i=1;i<=2*M;i++) if(!dfn[i]) tarjan(i); int flag=1; for(int i=1;i<=2*M;i++) if(color[i]==color[i+M]) {printf("NO\n");flag=0;break;} if(flag==1) printf("YES\n"); } return 0; }