[BZOJ1997][Hnoi2010]Planar 2-sat (联通分量) 平面图

1997: [Hnoi2010]Planar

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2317  Solved: 850
[Submit][Status][Discuss]

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

Sample Output

NO
YES

HINT

 

Source

Day1

 

太强辣。

平面图的边数不大于3*n-6剪枝。

先将环提出来,对于剩下的边,我们可以选择在环外连还是在环内连。

对于不相交的边,显然在环外连和在环内连都不会相交。

对于相交的边,显然不能同时在环外连或在环内连。只能一个在环外一个在环内。

将一条边拆为环外、环内两条边,构造2-sat。

判断2*i和2*i-1是否在同一个联通分量里。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #define LL long long
 9 #define mod 19650827
10 using namespace std;
11 int read() {
12     char ch=getchar();int x=0,f=1;
13     while(!isdigit(ch)){ch=getchar();}
14     while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
15     return x;
16 }
17 int T;
18 int n,m;
19 struct data {
20     int u,v;
21 }a[10005];
22 int pos[10005];
23 int cnt=0;
24 int head[10005],cntt;
25 struct edge {
26     int to,next;
27 }e[1000002];
28 void add(int u,int v) {e[cntt].to=v;e[cntt].next=head[u];head[u]=cntt++;}
29 int dfn[10005],low[10005],inq[10005],sz;
30 int sta[10005],top,bl[10005],scc;
31 void tarjan(int now) {
32     dfn[now]=low[now]=++sz;
33     sta[++top]=now;inq[now]=1;
34     for(int i=head[now];i>=0;i=e[i].next) {
35         int to=e[i].to;
36         if(!dfn[to]) {tarjan(to);low[now]=min(low[now],low[to]);}
37         else if(inq[to]) {low[now]=min(low[now],dfn[to]);}
38     }
39     if(low[now]==dfn[now]) {
40         int x=-1;
41         scc++;
42         while(x!=now) {
43             x=sta[top--];inq[x]=0;
44             bl[x]=scc;
45         }
46     }
47 }
48 int main() {
49     T=read();
50     while(T--) {
51         cnt=0;cntt=0;top=0;scc=0;sz=0;
52         memset(head,-1,sizeof(head));
53         memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
54         memset(inq,0,sizeof(inq));
55         n=read(),m=read();
56         for(int i=1;i<=m;i++) a[i].u=read(),a[i].v=read();
57         for(int i=1;i<=n;i++) pos[read()]=i;
58         if(m>3*n-6){printf("NO\n");continue;}
59         for(int i=1;i<=m;i++) {
60             int c=abs(pos[a[i].u]-pos[a[i].v]);
61             if(c==1||(max(pos[a[i].u],pos[a[i].v])==n&&min(pos[a[i].u],pos[a[i].v])==1)) continue;
62             a[++cnt]=a[i];
63         }
64         for(int i=1;i<=cnt;i++) {
65             for(int j=i+1;j<=cnt;j++) {
66                 int t1=pos[a[i].u],t2=pos[a[i].v];
67                 if(t1>t2) swap(t1,t2);
68                 int t3=pos[a[j].u],t4=pos[a[j].v];
69                 if(t3>t4) swap(t3,t4);
70                 if((t1<t3&&t2<t4&&t2>t3)||(t1>t3&&t2>t4&&t1<t4)) {
71                     add(2*i-1,2*j);add(2*j,2*i-1);
72                     add(2*i,2*j-1);add(2*j-1,2*i);
73                 }
74             }
75         }
76         for(int i=1;i<=2*cnt;i++) if(!dfn[i]) tarjan(i);
77         bool flag=1;
78         for(int i=1;i<=cnt;i++) if(bl[2*i]==bl[2*i-1]){printf("NO\n");flag=0;break;}
79         if(flag)printf("YES\n");
80     }
81 }
View Code

 

posted @ 2017-11-09 16:10  wls001  阅读(174)  评论(0编辑  收藏  举报