bzoj 1997 [Hnoi2010]Planar——2-SAT+平面图的一个定理
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1997
平面图的一个定理:若边数大于(3*点数-6),则该图不是平面图。
然后就可以2-SAT了!
注意把输入读完再用定理continue!!!
注意边是元素,所以是i+m,而且数组也应开成M<<1!!!
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=405,M=605; int T,n,m,hd[M<<1],xnt,x[M],y[M],mp[N]; int dfn[M<<1],low[M<<1],tim,sta[M<<1],top,col[M<<1],cnt; bool ins[M<<1],flag; struct Ed{ int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {} }ed[(M*M)<<1]; bool check(int i,int j) { int x1=mp[x[i]],y1=mp[y[i]],x2=mp[x[j]],y2=mp[y[j]]; if(x1>y1)swap(x1,y1); if((x2>x1&&x2<y1&&(y2>y1||y2<x1))||(y2>x1&&y2<y1&&(x2>y1||x2<x1)))return true; return false; } void add(int i,int j) { ed[++xnt]=Ed(hd[i],j+m);hd[i]=xnt; ed[++xnt]=Ed(hd[j],i+m);hd[j]=xnt; ed[++xnt]=Ed(hd[i+m],j);hd[i+m]=xnt; ed[++xnt]=Ed(hd[j+m],i);hd[j+m]=xnt; } void tarjan(int cr) { dfn[cr]=low[cr]=++tim; sta[++top]=cr;ins[cr]=1; for(int i=hd[cr],v;i;i=ed[i].nxt) if(!dfn[v=ed[i].to])tarjan(v),low[cr]=min(low[cr],low[v]); else if(ins[v])low[cr]=min(low[cr],dfn[v]); if(dfn[cr]==low[cr]) { cnt++; while(sta[top]!=cr)col[sta[top]]=cnt,ins[sta[top--]]=0; top--;col[cr]=cnt;ins[cr]=0; } } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m);int z; for(int i=1;i<=m;i++)scanf("%d%d",&x[i],&y[i]); for(int i=1;i<=n;i++) scanf("%d",&z),mp[z]=i; if(m>3*n-6){printf("NO\n");continue;}//先把输入都读完再continue!!! memset(hd,0,sizeof hd);xnt=0; for(int i=1;i<m;i++) for(int j=i+1;j<=m;j++) if(check(i,j))add(i,j); memset(dfn,0,sizeof dfn);tim=0;cnt=0; for(int i=1;i<=2*m;i++)if(!dfn[i])tarjan(i); flag=0; for(int i=1;i<=m;i++) if(col[i]==col[i+m]){flag=1;break;} if(flag)printf("NO\n"); else printf("YES\n"); } return 0; }