BZOJ1997 Planet

题目

若能将无向图 G=(V,E)画在平面上使得任意两条无重合顶点的边不相交,则称 G 是平面图。

判定一个图是否为平面图的问题是图论中的一个重要问题。

现在假设你要判定的是一类特殊的图,图中存在一个包含所有顶点的环,即存在哈密顿回路。

请你判定它们是否是平面图。

输入格式
第一行包含正整数T,表示共有T组测试数据。

每组测试数据第一行包含两个整数 N 和 M,分别表示对应图的顶点数和边数。

之后M行,每行包含两个整数u和v,表示对应图的一条边(u,v),输入数据保证所有边仅出现一次。

最后一行,包含 N 个整数,从左到右表示对应图中的一个哈密顿回路。

输出格式

输出共T行。

如果第 i 组数据对应的图是平面图,则第 i 行输出“YES”,否则输出“NO”

数据范围

T≤100,3≤N≤200,M≤10000

输入样例:

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

题解

明显的 2-SAT

主要是证明一下, 当 m > 3*n - 6, 必定不存在平面图

你问为什么要证?不然超时啊

平面图:设无向图G,若能将G画在一个平面上,使得任何两条边仅在顶点处相交,则称G是具有平面性质的图,简称平面图,否则称G是非平面图。

在平面图G中,G的边将其所在的平面划分成的区域称为面,有限的区域称为有限面或内部面,无线的区域称为无限面或外部面,
包围面的边称为该面的边界,包围每个面的所有边组成的回路长度称为该面的次数(桥计算两次)。

那么有, 平面图G所有面的次数之和等于边数的两倍(类似于握手定理)。

欧拉定理: 对于一个简单通平面图, 设G是一个面数为 f 的(n,m)平面图,则 n-m + f = 2.(归纳法证)

推论1, 设G是一个面数为 f 的(n,m)平面图,且有p个连通分支,则 n-m+f = p + 1, 所有连通分支共用一个无限面

推论2, 假设G是一个面数为 f 的(n,m)连通简单平面图,n≥3,每个面的次数至少是 p(p≥3),则m≤(n-2)*p/(p-2)。//n>=3, 则边数 m>=2,无限面的次数至少为2*2
      有定义出发, 面的次数之和等于边数两倍, 故 f*p ≤ 2 * m, 带入欧拉公式可得上式

根据上述推论2, 这道题每个面的次数至少为 3, 故 m <= 3 * n - 6

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 2e2 + 5, M = 1e4 + 5;

int n, m, _, k;
PII e[M];
int f[M << 1], id[N];
 
int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
 
bool check(int a, int b, int c) {
    a = id[a], b = id[b], c = id[c];
    if(a > b) swap(a, b);
    return a < c && b > c;
}

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> m;
        rep (i, 1, m) cin >> e[i].fi >> e[i].se, f[i] = i, f[i + m] = i + m;
        rep (i, 1, n) cin >> k, id[k] = i;
        if (m > 3 * n - 6) { cout << "NO\n"; continue; }
        rep (i, 1, m)
            rep (j, i + 1, m) {
                if (e[i].fi == e[j].fi || e[i].fi == e[j].se || e[i].se == e[j].fi || e[i].se == e[j].se) continue;
                if (check(e[i].fi, e[i].se, e[j].fi) == check(e[i].fi, e[i].se, e[j].se)) continue;
                f[find(i)] = find(j + m), f[find(j)] = find(i + m);
            }
        bool f = 1;
        rep (i, 1, m) if (find(i) == find(i + m)) { f = 0; break; }
        cout << (f ? "YES\n" : "NO\n");
    }
    return 0;
}
posted @ 2020-09-29 16:22  洛绫璃  阅读(152)  评论(0编辑  收藏  举报