题目
若能将无向图 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
"; 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
" : "NO
");
}
return 0;
}