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
题解
把题目给的哈密顿回路拎出来。
对于不在哈密顿回路上的边,在平面图上要么把它放在环内部要么放在环外部。而对于相交的两条边,必然即不能同时放在内部也不能同时放在外部。
那么可以建立2-SAT模型:
去掉哈密顿回路上边后,设还剩m条边。
将这m条边分为m组,每组中两条边起点终点相同一条在外一条在里。这两条边中只能选择一条。而对于两条相交的边,一条取了外面的另一条就必须取里面的,反之同理。所以在2-SAT中从
A1i
向
A2j
连边,
A2i
向
A1j
连边。缩点后若存在
A1i
和
A2i
同属一个强联通分量,那么一定不是平面图,否则就是。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int N = 10000 + 10, M = 1000000 + 10;
int n, m;
int u[N], v[N], pos[N];
int to[M], nxt[M], tot;
int hd[N], dfn[N], low[N], q[N], bl[N], dfs_clock, scc, top;
bool inq[N];
bool init(){
n = read(); m = read();
for(int i = 1; i <= m; i++)
u[i] = read(), v[i] = read();
int x;
for(int i = 1; i <= n; i++){
x = read();
pos[x] = i;
}
if(m > n * 3 - 6) return true;
memset(hd, 0, sizeof(hd));
return false;
}
inline void insert(int u, int v){to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot;}
void build(){
int tmp = 0;
for(int i = 1; i <= m; i++){
u[i] = pos[u[i]]; v[i] = pos[v[i]];
if(u[i] > v[i]) swap(u[i], v[i]);
if(v[i] == u[i] + 1 || u[i] == 1 && v[i] == n) continue;
u[++tmp] = u[i]; v[tmp] = v[i];
}
m = tmp;
for(int i = 1; i <= m; i++)
for(int j = i + 1; j <= m; j++)
if((u[i] < u[j] && u[j] < v[i] && v[i] < v[j]) || (u[j] < u[i] && u[i] < v[j] && v[j] < v[i])){
insert(2*i-1, 2*j);
insert(2*i, 2*j-1);
insert(2*j-1, 2*i);
insert(2*j, 2*i-1);
}
}
void tarjan(int u){
dfn[u] = low[u] = ++dfs_clock;
inq[u] = 1; q[++top] = u;
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i];
if(dfn[v] == -1){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(inq[v])
low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
int now = -1;
scc++;
while(now != u){
now = q[top--]; inq[now] = 0;
bl[now] = scc;
}
}
}
void find_scc(){
memset(dfn, -1, sizeof(dfn));
memset(inq, 0, sizeof(inq));
memset(low, 1, sizeof(low));
for(int i = 1; i <= m<<1; i++)
if(dfn[i] == -1) tarjan(i);
}
bool check(){
for(int i = 1; i <= m; i++)
if(bl[i*2] == bl[i*2-1]) return false;
return true;
}
void work(){
int t = read();
while(t--){
if(init()){
puts("NO");
continue;
}
build();
find_scc();
if(check()) puts("YES");
else puts("NO");
}
}
int main(){
work();
return 0;
}