BZOJ1997 : [HNOI2010] Planar (2-SAT)

题意

给你一个有 n 个点的图 里面有 m 条边

并给你图上一条哈密顿回路 然后让你判断它是否为平面图

平面图就是存在一种情况 使得边两两不相交 数据共 T

(T100,3n200,m10000)

题解

这题是我见过最不裸的 2SAT 了 根本不会啊

判断平面图 有一些鬼畜的算法可以做 但根本不会啊

这题比较特殊 给了一条哈密顿回路 那么我们可以利用这个性质

不难发现 如果两条边会相交 那么他们不能同时存在 在 哈密顿圈 内 或者 外面

这样 我们对于原图中每条边就变成 2SAT 上的点然后去判断就行了

至于判边相交 考虑如下一种情况

pic

我们将这个环重新标号 标为 16

然后如果两条边 (设为 uiviujvj 强制 ui<uj,ui<vi,uj<vj ) 会相交 那么我们就有一个不等式

ui<uj<vi<vj

所有相交情况都可以这样转化

但数据组数多 边的范围原超过点的范围 可能会TLE

所以我们就可以用个性质进行一些优化

平面图上 边数 E 和 点数 V 满足 EV36

这个一开始直接判就行了qwq

代码

有一些鬼畜的地方 就是点和边的范围 以及 他们一开始清空的范围

/************************************************************** Problem: 1997 User: zjp_shadow Language: C++ Result: Accepted Time:180 ms Memory:10440 kb ****************************************************************/ #include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;} inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() { int x = 0, fh = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * fh; } void File() { #ifdef zjp_shadow freopen ("1997.in", "r", stdin); freopen ("1997.out", "w", stdout); #endif } const int N = 110000 << 1, M = 100100 << 1; struct Two_SAT { #define Travel(i, u, v) for(int i = Head[u], v = to[i]; i; i = Next[i], v = to[i]) int Head[N], Next[M], to[M], e, n; void add_edge(int u, int v) { to[++ e] = v; Next[e] = Head[u]; Head[u] = e; } void Add(int x, int xv, int y, int yv) { x = x << 1 | xv; y = y << 1 | yv; add_edge(x, y); add_edge(y ^ 1, x ^ 1); } void Init(int n) { this -> n = n; e = 0; For (i, 1, n * 2 + 10) Head[i] = 0; } int sccno[N], scc_cnt; int clk, dfn[N], lowlink[N]; int sta[N], top; void Tarjan(int u) { lowlink[u] = dfn[u] = ++ clk; sta[++ top] = u; Travel(i, u, v) if (!dfn[v]) Tarjan(v), chkmin(lowlink[u], lowlink[v]); else if (!sccno[v]) chkmin(lowlink[u], dfn[v]); if (lowlink[u] == dfn[u]) { ++ scc_cnt; for (;;) { int x = sta[top --]; sccno[x] = scc_cnt; if (x == u) break; } } } bool Solve() { For (i, 1, n * 2 + 10) dfn[i] = sccno[i] = lowlink[i] = 0; scc_cnt = clk = top = 0; For (i, 1, n * 2 + 1) if (!dfn[i]) Tarjan(i); For (i, 1, n) if (sccno[i << 1] == sccno[i << 1 | 1]) return false; return true; } } T; struct Edge{ int u, v; inline bool operator < (const Edge &rhs) const { return (u ^ rhs.u) ? u < rhs.u : v < rhs.v; } } lt[M]; int ver[N], num[N]; int main () { File(); int cases = read(); while (cases --) { int n = read(), m = read(); For (i, 1, m) { lt[i].u = read(); lt[i].v = read(); } For (i, 1, n) { ver[i] = read(); num[ver[i]] = i; } if (m > 3 * n - 6) { puts("NO"); continue; } For (i, 1, m) { lt[i].u = num[lt[i].u]; lt[i].v = num[lt[i].v]; if (lt[i].u > lt[i].v) swap(lt[i].u, lt[i].v); } sort(lt + 1, lt + 1 + m); T.Init(n); For (i, 1, m) For (j, i + 1, m) { if (lt[i].u == lt[i].v - 1 || (lt[i].u == 1 && lt[i].v == n)) continue ; if (lt[i].u < lt[j].u && lt[j].u < lt[i].v && lt[i].v < lt[j].v) { T.Add(i, 1, j, 0); T.Add(i, 0, j, 1); } } puts(T.Solve() ? "YES" : "NO"); } return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/8721593.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(201)  评论(5编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示