[BZOJ 1997][Hnoi2010]Planar

1997: [Hnoi2010]Planar

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2167  Solved: 804
[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

题解

思路非常清奇...

首先图里存在哈密顿回路而且输入中已经给出, 那么如果要判断这个图是否是平面图, 我们首先一定会把这个哈密顿回路画在上面, 而且这部分没有优化余地.

然后剩下的不在环上的边则有两种选择: 从环里穿过去或者从环外绕过去. 根据边所连接的两个节点在哈密顿回路中的顺序确定如果边同时在环内是否会相交, 如果会相交的话这两条边必须分居哈密顿环两侧. 处理出所有之后判断可行性就好了

所以这个充满 $NPC$ 问题的题面实际上是个 $2-SAT$ ...QAQ

然后就是 $2-SAT$ 要加反向边(NOI 2017的惨痛教训)

参考代码

GitHub

  1 #include <stack>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <iostream>
  6 #include <algorithm>
  7 
  8 const int MAXEX=1e6+10;
  9 const int MAXE=1e4+10;
 10 const int MAXV=2e3+10;
 11 
 12 struct Edge{
 13     int from;
 14     int to;
 15     Edge* next;
 16 };
 17 Edge E[MAXE];
 18 Edge Ex[MAXEX];
 19 Edge* head[MAXV];
 20 Edge* top=E;
 21 
 22 int v;
 23 int e;
 24 int clk;
 25 int scc;
 26 int dfn[MAXV];
 27 int low[MAXV];
 28 int pos[MAXV];
 29 int cycle[MAXV];
 30 int belong[MAXV];
 31 
 32 bool inStack[MAXV];
 33 
 34 std::stack<int> s;
 35 
 36 void Tarjan(int);
 37 void Initialize();
 38 void Insert(int,int);
 39 
 40 int main(){
 41     int T;
 42     scanf("%d",&T);
 43     while(T--){
 44         Initialize();
 45         if(e>3*v-6){
 46             puts("NO");
 47             continue;
 48         }
 49         int cnt=0;
 50         for(int i=0;i<e;i++){
 51             E[i].from=pos[E[i].from];
 52             E[i].to=pos[E[i].to];
 53             if(E[i].from>E[i].to)
 54                 std::swap(E[i].from,E[i].to);
 55             if(E[i].to-E[i].from==1||E[i].from==1&&E[i].to==v)
 56                 continue;
 57             else
 58                 E[cnt++]=E[i];
 59         }
 60         for(int i=0;i<cnt;i++){
 61             for(int j=i+1;j<cnt;j++){
 62                 if((E[i].from<E[j].from&&E[i].to<E[j].to&&E[i].to>E[j].from)||(E[i].from>E[j].from&&E[i].to>E[j].to&&E[i].from<E[j].to)){
 63                     Insert(2*i+1,2*j);
 64                     Insert(2*i,2*j+1);
 65                     Insert(2*j+1,2*i);
 66                     Insert(2*j,2*i+1);
 67                 }
 68             }
 69         }
 70         for(int i=0;i<2*cnt;i++){
 71             if(dfn[i]==0)
 72                 Tarjan(i);
 73         }
 74         bool ans=true;
 75         for(int i=0;i<cnt;i++){
 76             if(belong[2*i]==belong[2*i+1]){
 77                 ans=false;
 78                 break;
 79             }
 80         }
 81         if(ans)
 82             puts("YES");
 83         else
 84             puts("NO");
 85     }
 86     return 0;
 87 }
 88 
 89 inline void Insert(int from,int to){
 90     top->from=from;
 91     top->to=to;
 92     top->next=head[from];
 93     head[from]=top++;
 94 }
 95 
 96 void Tarjan(int root){
 97     dfn[root]=low[root]=++clk;
 98     inStack[root]=true;
 99     s.push(root);
100     for(Edge* i=head[root];i!=NULL;i=i->next){
101         if(dfn[i->to]==0){
102             Tarjan(i->to);
103             low[root]=std::min(low[root],low[i->to]);
104         }
105         else if(inStack[i->to])
106             low[root]=std::min(low[root],dfn[i->to]);
107     }
108     if(low[root]==dfn[root]){
109         scc++;
110         int top;
111         do{
112             top=s.top();
113             belong[top]=scc;
114             inStack[top]=false;
115             s.pop();
116         }while(top!=root);
117     }
118 }
119 
120 inline void Initialize(){
121     memset(head,0,sizeof(head));
122     memset(low,0,sizeof(low));
123     memset(dfn,0,sizeof(dfn));
124     clk=scc=0;
125     top=Ex;
126     scanf("%d%d",&v,&e);
127     for(int i=0;i<e;i++){
128         scanf("%d%d",&E[i].from,&E[i].to);
129     }
130     for(int i=1;i<=v;i++){
131         scanf("%d",cycle+i);
132         pos[cycle[i]]=i;
133     }
134 }
Backup

 

posted @ 2017-10-14 14:03  rvalue  阅读(251)  评论(0编辑  收藏  举报