当前位置: 首页 > news >正文

题解:Luogu P6898 [ICPC 2014 WF] Metal Processing Plant

题意

给定 \(n\),对于每个 \(1\leq i,j\leq n\),给出 \(d(i,j)\)。对于集合 \(S\),定义 \(D(S)=\max\limits_{i,j\in S}d(i,j)\)。将 \(\{1,2,\cdots,n\}\) 划分为两个集合 \(A,B\),最小化 \(D(A)+D(B)\)\(1\leq n\leq 200\)

题解

不妨钦定 \(D(A)\geq D(B)\),考虑枚举 \(A,B\) 中边权最大的边 \((a,b),(c,d)\),那么对于每条不为 \((a,b),(c,d)\) 的边 \((i,j)\)

  • \(d(i,j)>d(a,b)\),则 \(i,j\) 不能同时在 \(A\) 中。
  • \(d(i,j)>d(c,d)\),则 \(i,j\) 不能同时在 \(B\) 中。

显然是 2-SAT 的形式,直接做 Tarjan 判定是否有解就可以得到 \(\mathcal{O}(n^6)\) 的做法。

进一步优化,固定 \(A\) 中边权最大的边后,使用二分,check \(B\) 中的最大边权能不能 \(\leq x\)。时间复杂度降到 \(\mathcal{O}(n^4\log{n})\)

接下来是非常神仙的一步优化。我们从大到小枚举 \(A\) 中边权最大的边,建一个新图 \(G\),每枚举一条新边,就把这条边加入 \(G\) 中。考察若加入当前边 \((i,j)\) 后,\(G\) 中形成一个环说明什么:

  • 若该环为奇环,考察接下来某条将要枚举的边 \((i',j')\) 满足 \(d(i',j')<d(i,j)\),这时我们会要求前面的边不能同时出现在 \(A\) 中,也不能同时出现在 \(B\) 中,相当于做二分图染色,但是由于出现了奇环,必定无解。因此这种情况下,我们处理完当前边后就不必继续往后枚举了。
  • 若该环为偶环,则当前边必定不能作为 \(A\) 中的最大边。因为此时必然要求这条边连接的两个点同色,但是由于这两个点之间间隔了奇数个点,显然这是不可能的。因此这种情况下,我们直接跳过当前边。

于是 \(G\) 中至多有 \(n\) 条边,时间复杂度降为 \(\mathcal{O}(n^3\log{n})\),可以通过。

实现时可以使用带权并查集维护是否成环,以及连成了奇环还是偶环。

代码

放一下主要部分。

struct DSU {int fa[N], c[N];inline void init() { for (int i = 1; i <= n; ++i) fa[i] = i, c[i] = 0; }inline int find(int x) {if (x == fa[x]) return x;int fx = fa[x];return fa[x] = find(fa[x]), c[x] ^= c[fx], fa[x];}inline void unite(int x, int y) {int fx = find(x), fy = find(y);if (fx == fy) return;fa[fx] = fy, c[fx] ^= c[x] ^ c[y] ^ 1;}
} d;inline void tarjan(int x) {low[x] = dfn[x] = ++stmp, in_stk[stk[++top] = x] = 1;for (int y : G[x]) {if (!dfn[y]) tarjan(y), chk_min(low[x], low[y]);else if (in_stk[y]) chk_min(low[x], dfn[y]);}if (low[x] == dfn[x]) {++tot; int p;do p = stk[top--], in_stk[p] = 0, id[p] = tot; while (p != x);}
}
inline bool sat(int w1, int w2) {for (int i = 1; i <= n << 1; ++i) G[i].clear();for (int i = 1; i <= sze; ++i) {int x = e[i].x, y = e[i].y, z = e[i].z;if (z > w1) G[x].push_back(y + n), G[y].push_back(x + n);if (z > w2) G[x + n].push_back(y), G[y + n].push_back(x);}fill(dfn + 1, dfn + (n << 1) + 1, 0), stmp = tot = 0;for (int i = 1; i <= n << 1; ++i) if (!dfn[i]) tarjan(i);for (int i = 1; i <= n; ++i) if (id[i] == id[i + n]) return 0;return 1;
}int main() {ios::sync_with_stdio(0), cin.tie(0);cin >> n;for (int i = 1; i <= n; ++i) for (int j = i + 1, w; j <= n; ++j) cin >> w, e[++sze] = {i, j, w};if (n <= 2) return cout << "0", 0;sort(e + 1, e + sze + 1), d.init();for (int i = sze; i; --i) {int x = e[i].x, y = e[i].y, fx = d.find(x), fy = d.find(y);if (fx != fy) d.unite(x, y);else if (d.c[x] != d.c[y]) continue;int l = 0, r = i - 1, mn = INF;while (l <= r) {int mid = l + r >> 1;if (sat(e[i].z, e[mid].z)) mn = e[mid].z, r = mid - 1;else l = mid + 1;}chk_min(ans, e[i].z + mn);d.find(x), d.find(y);if (d.c[x] == d.c[y]) break;}cout << ans;return 0;
}
http://www.jsqmd.com/news/17852/

相关文章:

  • 32-腾讯IM接入资料和定价
  • 题解:AtCoder ARC207A Affinity for Artifacts
  • 题解:Luogu P9260 [PA 2022] Miny
  • 题解:Luogu P13544 [OOI 2022] Serious Business
  • 题解:Luogu P14254 分割(divide)
  • 31_创蓝短信接入资料和定价
  • 02.Python百行代码实现抽奖系统
  • CSP-S 35
  • 题解:P11662 [JOI 2025 Final] 方格染色 / Grid Coloring
  • CSP-S 32 多校5
  • CSP-S 33
  • CSP-S 29
  • 10.20每日总结
  • CSP-S 31
  • 2025网络安全振兴杯wp
  • 后缀树
  • ES原理、zookeeper、kafka
  • CF1606E Arena 题解(动态规划)
  • 服务器CPU市场概况2025
  • CSP-S 24
  • 正睿 2025 NOIP20 连测 Day5 做题记录
  • 29-腾讯云COS接入指南与价格说明
  • LLM学习记录DAY7
  • CSP-S 23
  • Recall
  • CSP-S 20
  • Flutter应用设置插件 - 轻松打开iOS和Android系统设置
  • CSP-S 22
  • /usr/bin/sudo 二进制文件的权限有问题,导致所有用户都无法使用 sudo
  • MySQL 8.0.43社区版本安装流程