Luogu3209 HNOI2010 平面图判定 平面图、并查集

传送门

题意:$T$组数据,每组数据给出一个$N$个点,$M$条边,并存在一个$N$元环的图,试判断其是否为一个可平面图(如果存在一种画法,使得该图与给出的图同构且边除了在顶点处以外互相不相交,则称其为可平面图)$T \leq 100 , N \leq 200 , M \leq 10000$


关于平面图的性质可以参照这一个PPT

我们需要用到平面图的一个推论:在极大平面图(不能再加边的平面图)上,$M = 3 \times N - 6$(PPT里面有证明)

所以对于$M > 3 \times N - 6$的情况可以直接判定为NO,这样我们需要处理的问题的边数变为了$O(N)$级别。

接下来我们考虑$N$元环的作用。一个$N$元环将整个图分成了两个部分,一个在环内,一个在环外,而环内和环外连的边不能在非顶点处相交。这个问题可以通过并查集来实现,将一条边看做两个点(一个表示不与当前边排斥,一个表示与当前边排斥),对于互相排斥的边在并查集上合并,最后考虑是否存在一条边的两个点在一个集合内即可。

 1 #include
 2 using namespace std;
 3 
 4 inline int read(){
 5     int a = 0;
 6     bool f = 0;
 7     char c = getchar();
 8     while(!isdigit(c)){
 9         if(c == '-')
10             f = 1;
11         c = getchar();
12     }
13     while(isdigit(c)){
14         a = (a << 3) + (a << 1) + (c ^ '0');
15         c = getchar();
16     }
17     return f ? -a : a;
18 }
19 
20 struct Edge{
21     int start , end;
22 }Ed[10010];
23 map < int , int > lsh;
24 int N , M , cnt , fa[20010];
25 
26 bool cmp(Edge a , Edge b){
27     return a.start < b.start;
28 }
29 
30 inline void init(){
31     for(int i = 1 ; i <= M << 1 ; i++)
32         fa[i] = i;
33 }
34 
35 int find(int x){
36     return fa[x] == x ? x : (fa[x] = find(fa[x]));
37 }
38 
39 int main(){
40 #ifdef LG
41     freopen("3209.in" , "r" , stdin);
42     freopen("3209.out" , "w" , stdout);
43 #endif
44     for(int T = read() ; T ; T--){
45         N = read();
46         M = read();
47         for(int i = 1 ; i <= M ; i++){
48             Ed[i].start = read();
49             Ed[i].end = read();
50         }
51         lsh.clear();
52         for(int i = 1 ; i <= N ; i++)
53             lsh[read()] = i;
54         if(M > 3 * N - 6){
55             cout << "NO" << endl;
56             continue;
57         }
58         for(int i = 1 ; i <= M ; i++){
59             Ed[i].start = lsh[Ed[i].start];
60             Ed[i].end = lsh[Ed[i].end];
61             if(Ed[i].start > Ed[i].end)
62                 swap(Ed[i].start , Ed[i].end);
63         }
64         init();
65         sort(Ed + 1 , Ed + M + 1 , cmp);
66         bool f = 1;
67         for(int i = 1 ; f && i <= M ; i++){
68             for(int j = i - 1 ; f && j ; j--)
69                 if(Ed[j].end > Ed[i].start && Ed[j].end < Ed[i].end && Ed[j].start < Ed[i].start){
70                     fa[find(j)] = find(i + M);
71                     fa[find(i)] = find(j + M);
72                     if(find(i) == find(i + M) || find(j) == find(j + M))
73                         f = 0;
74                 }
75         }
76         cout << (f ? "YES" : "NO") << endl;
77     }
78     return 0;
79 }

转载于:https://www.cnblogs.com/Itst/p/9852151.html

你可能感兴趣的:(Luogu3209 HNOI2010 平面图判定 平面图、并查集)