当前位置: 首页 > 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.hskmm.com/?act=detail&tid=35329

相关文章:

  • 20251020
  • 32-腾讯IM接入资料和定价
  • 题解:AtCoder ARC207A Affinity for Artifacts
  • 构造单
  • [笔记]高斯消元
  • 半导体设备各细分领域的国内外龙头公司
  • CSP-S 34
  • 02.Python百行代码实现抽奖系统
  • CSP-S 35
  • CSP-S 29
  • 2025网络安全振兴杯wp
  • 10.20每日总结
  • CSP-S 31
  • 后缀树
  • ES原理、zookeeper、kafka
  • CF1606E Arena 题解(动态规划)
  • 服务器CPU市场概况2025
  • CSP-S 24
  • 读书笔记:深入理解java虚拟机
  • CSP-S 19
  • CSP-S 20
  • Flutter应用设置插件 - 轻松打开iOS和Android系统设置
  • CSP-S 22
  • Project. 2025.11化学小组pre
  • MySQLDay1
  • 蛋白表达标签:重组蛋白研究的精妙引擎
  • 106.腾讯地图位置服务再出错
  • 心理咨询系统
  • Adaptive Learning Rate(自适应学习率) - -一叶知秋
  • Luogu P10034 「Cfz Round 3」Circle 题解 [ 蓝 ] [ 背包 DP ] [ 质数筛 ] [ 图论 ] [ 构造 ]