感觉 (2-SAT) 的题目跟网络流有点点像,都是考虑怎么建图,然后跑板子
而 (2-SAT) 的题目的一个建图的思路就是转换成一真一假的格式,然后就比较好
Description
给一张图和一条图上的哈密尔顿回路,判定是不是可以把它转换成一个平面图
(n leq 200),(m leq 10000)
多组数据((doc)我多测没清空,(WA)了好几发)
Solution
先是一个实用 (trick) :平面图中,(m leq 3n-6)
证明等学平面图的时候再说吧
把这一个哈密尔顿回路想成平面上的一个圆(多边形)
而非回路上的点就是圆上的弦(多边形对角线),或者连在环外部
两条弦相交的条件还得满足
for (int i = 1; i < m; ++i) {
for (int j = i + 1; j <= m; ++j) {
int p = id[ex[i]], q = id[ey[i]], r = id[ex[j]], s = id[ey[j]];
if (p > q)
swap(p, q);
if (r > s)
swap(r, s);
if ((p < r && q > r && q < s || (r < p && s > p && s < q)))
add(i, j + m), add(i + m, j), add(j, i + m), add(j + m, i);
}
}
反正博主是懂了(画图就可以感性理解)
然后跑 (tarjan) 就没了
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm {
inline int read() {
int res = 0, f = 1;
char k;
while (!isdigit(k = getchar()))
if (k == '-')
f = -1;
while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
return res * f;
}
const int N = 1e4 + 10;
int dfn[N], low[N], scc[N], st[N], tot, tim, top, u[N], v[N], c[N], ex[N], ey[N], now;
vector<int> g[N];
int n, id[N], m;
bool f[300][300], vis[N];
inline void add(int u, int v) { return g[u].push_back(v), void(); }
inline void tarjan(int x) {
dfn[x] = low[x] = ++tim;
vis[x] = 1;
st[++top] = x;
int sz = g[x].size();
for (int i = 0; i < sz; ++i) {
int t = g[x][i];
if (!dfn[t])
tarjan(t), low[x] = min(low[x], low[t]);
else if (vis[t])
low[x] = min(low[x], dfn[t]);
}
if (dfn[x] == low[x]) {
++tot;
while (st[top] != x) scc[st[top]] = tot, vis[st[top--]] = 0;
scc[st[top]] = tot, vis[st[top--]] = 0;
}
return;
}
#define cl(x) memset(x, 0, sizeof(x))
inline void prework() {
cl(dfn);
cl(scc);
cl(st);
cl(u);
cl(v);
cl(ex);
now = 0;
tim = 0;
tot = 0;
top = 0;
cl(ey);
cl(id);
cl(vis);
cl(f);
for (int i = 1; i < N; ++i) g[i].clear();
return;
}
inline void work() {
n = read();
m = read();
for (int i = 1; i <= m; ++i) {
u[i] = read();
v[i] = read();
if (u[i] > v[i])
swap(u[i], v[i]);
}
for (int i = 1, x, y; i <= n; ++i) {
c[i] = read();
id[c[i]] = i;
if (i > 1) {
x = c[i];
y = c[i - 1];
f[min(x, y)][max(x, y)] = 1;
}
}
if (m > 3 * n - 6)
return puts("NO"), void();
f[min(c[1], c[n])][max(c[1], c[n])] = 1;
for (int i = 1; i <= m; ++i) {
if (f[u[i]][v[i]])
continue;
ex[++now] = u[i], ey[now] = v[i];
}
//把非回路上的点找出来
m = now;
for (int i = 1; i < m; ++i) {
for (int j = i + 1; j <= m; ++j) {
int p = id[ex[i]], q = id[ey[i]], r = id[ex[j]], s = id[ey[j]];
if (p > q)
swap(p, q);
if (r > s)
swap(r, s);
if ((p < r && q > r && q < s || (r < p && s > p && s < q)))
add(i, j + m), add(i + m, j), add(j, i + m), add(j + m, i);
}
}
for (int i = 1; i <= m * 2; ++i)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= m; ++i)
if (scc[i] == scc[i + m])
return puts("NO"), void();
puts("YES");
return;
}
signed main() {
int T = read();
while (T--) prework(), work();
return 0;
}
} // namespace yspm
signed main() { return yspm::main(); }