题解:CF1666K Kingdom Partition
感觉很深刻的题目。
题意:给出一张带权图,要求划分为三个点集 \(A,B,C\),代价为,\(A,B\) 分别的导出子图中的边权和乘二加上 \(A,C\) 之间的边权和加上 \(B,C\) 之间的边权和,限定点 \(a\) 属于 \(A\),点 \(b\) 属于 \(B\),求最小值和构造。\(n\le 10^3\)。
做法:
感觉直接看上去有一点什么闭合子图之类的感觉,就是我需要通过割的方式去刻画一下被哪个集合选入,然后发现我连两个集合都不会做且是 NP-hard 问题,遂倒闭。
点开题解,发现里面有个非常深刻的刻画:
最小割可以被描述为:记 \(x_u\) 代表是否被源点集合包括,那么求得就是 \(\sum\limits_{(u,v)\in E}w_{u,v}x_u(1-x_v)\)。
那感觉感觉我们就得把这个题进行一定的推导转化成这种形式。
直接记 \(x_{u,0/1/2}\) 代表是否选入 \(A/B/C\),把题目的柿子用这个东西写出来并且带入一下 \(x_{u,0}+x_{u,1}+x_{u,2}=1\),相信大家都会化简,最后变成这样:
\[\sum_{(u,v)\in E}w_{u,v}(x_{u,0}(1-x_{v,1})+(1-x_{u,0})x_{v,1}+x_{u,1}(1-x_{v,0})+(1-x_{u,1})x_{v,0}
\]
发现这个就是上面最小割的形式,所以我们把每个点拆成两个,对应连边即可。强制钦定的直接连极大值即可。
还有一个问题,这样连边为什么不会出现 \(x_{u,0}=x_{u,1}=1\) 的问题,我们假设有这样的,记为 \(D\) 类点,按照柿子讨论一下 \(v\) 为 \(A,B,C,D\) 类点时与 \(u\) 为 \(D\) 类点的贡献,发现完全不如调整为 \(C\) 类点,所以就不会有这种情况。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e3 + 5, inf = 1e18;
struct Edge {
int to, fl, rev;
};
struct Graph {
vector<Edge> e[maxn];
void add(int x, int y, int w) {
e[x].push_back(Edge{y, w, e[y].size()});
e[y].push_back(Edge{x, 0, e[x].size() - 1});
}
int dep[maxn], s, t;
bool bfs() {
queue<int> q; q.push(s);
memset(dep, 0x3f, sizeof(dep)), dep[s] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < e[u].size(); i++) {
Edge v = e[u][i];
if(v.fl && dep[v.to] > dep[u] + 1) {
dep[v.to] = dep[u] + 1;
q.push(v.to);
}
}
}
return dep[t] != dep[t + 1];
}
int maxflow, cur[maxn];
int dfs(int u, int flow) {
if(u == t || !flow)
return flow;
int use = 0;
for (cur[u]; cur[u] < e[u].size(); cur[u]++) {
Edge v = e[u][cur[u]];
if(dep[v.to] == dep[u] + 1 && v.fl) {
int f = dfs(v.to, min(flow - use, v.fl));
e[u][cur[u]].fl -= f, e[v.to][v.rev].fl += f; use += f;
if(use == flow)
break;
}
}
return use;
}
int dinic(int S, int T) {
maxflow = 0;
s = S, t = T;
while(bfs())
memset(cur, 0, sizeof(cur)),
maxflow += dfs(s, inf);
return maxflow;
}
int vis[maxn];
void srh(int u) {
if(vis[u])
return ;
vis[u] = 1;
for (int i = 0; i < e[u].size(); i++)
if(e[u][i].fl)
srh(e[u][i].to);
}
} G;
int n, m;
signed main() {
int a, b;
cin >> n >> m >> a >> b;
int s = 0, t = 2 * n + 1;
G.add(s, a, inf), G.add(a + n, t, inf), G.add(s, b + n, inf), G.add(b, t, inf);
for (int i = 1; i <= m; i++) {
int x, y, w; cin >> x >> y >> w;
G.add(x, y + n, w), G.add(y + n, x, w), G.add(x + n, y, w), G.add(y, x + n, w);
}
cout << G.dinic(s, t) << endl;
G.srh(s);
for (int i = 1; i <= n; i++) {
if(G.vis[i] && !G.vis[i + n])
cout << 'A';
else if(G.vis[i + n] && !G.vis[i])
cout << 'B';
else
cout << 'C';
}
cout << endl;
return 0;
}

浙公网安备 33010602011771号