神仙网络流题。
Description
Solution
考虑最小割,将每个点 \(u\) 拆成 \(L_u,R_u\) 两个点。对于每一条原图中的边 \((u,v,w)\),连双向边 \((L_u,R_v,w),(L_v,R_u,w)\),边权为 \(w\)。加入源汇后跑最小割,将所有点 \(u\) 划分为四类:
-
SS: \(L_u,R_u\) 均与源点 \(S\) 连通。
-
TT: \(L_u,R_u\) 均与汇点 \(T\) 连通。
-
ST: \(L_u,R_u\) 分别与 \(S,T\) 连通。
-
TS: \(L_u,R_u\) 分别与 \(T,S\) 连通。
考虑一条原图中的边 \((u,v,w)\),讨论 \(u,v\) 分别属于哪一类点,有 \(16\) 情况:
SS | TT | ST | TS | |
---|---|---|---|---|
SS | 0 | 2 | 1 | 1 |
TT | 2 | 0 | 1 | 1 |
ST | 1 | 1 | 2 | 0 |
TS | 1 | 1 | 0 | 2 |
\(0,1,2\) 分别表示产生的代价。
给出结论:在原图上,SS 与 TT 类点不会直接相连。这是因为,对于 SS 与 TT 类点的导出子图的每个连通块,若其中同时存在 SS,TT,则将该连通块全部换成 SS 严格更优。
从而,我们可以列出一张新的表格:
SS / TT | ST | TS | |
---|---|---|---|
SS / TT | 0 | 1 | 1 |
ST | 1 | 2 | 0 |
TS | 1 | 0 | 2 |
将 ST,TS,SS/TT 分别对应 Adrian, Beatrice and Cecilia 即可。
时间复杂度 \(O(\text{Dinic}(m,n))\)。实现有一定细节:
- \(S\) 连向 \(L_x\),\(R_x\) 连向 \(T\) 以保证 \(x\) 属于 Adrian,边权均为 \(\inf\)。
- \(S\) 连向 \(R_y\),\(L_y\) 连向 \(T\) 以保证 \(y\) 属于 Beatrice,边权均为 \(\inf\)。
- 对于每条原图中的边 \((u,v,w)\),需要连双向边 \((L_u,R_v,w),(L_v,R_u,w)\)。加上反悔用的反边,相当于多建了 \(8\) 条边。别人建的边比我少,好像只用 \(4\) 条,我自带大常数。
- 根据最后一轮 bfs 每个节点是否被访问过,可以确定其属性。
- 点数,边数虽然都是 \(O(n)\),但常数较大,数组不要开小了。
Solution
#include <bits/stdc++.h>
#define int long long
#define inf 1000000000000000007
using namespace std;
const int N=2005;
int read(){
int s=0,w=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') w=-w;ch=getchar();}
while (ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
return s*w;
}
int n,m,x,y,S,T,st,ed,ans,cnt=1;
int L[N],R[N],head[N],cur[N],dep[N],que[N];
struct edge{int nxt,to,f;}e[N<<4];
void add_edge(int u,int v,int f){e[++cnt]=edge{head[u],v,f},head[u]=cnt;}
void Add(int u,int v,int f){add_edge(u,v,f),add_edge(v,u,0);}
void Add_bir(int u,int v,int f){Add(u,v,f),Add(v,u,f);}
bool bfs(){
for (int i=S;i<=T;i++) cur[i]=head[i],dep[i]=0;
que[st=ed=1]=S,dep[S]=1;
while (st<=ed){
int u=que[st++];
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if (!dep[v]&&e[i].f) dep[v]=dep[u]+1,que[++ed]=v;
}
}
return dep[T];
}
int dfs(int u,int Flow){
if (u==T) return Flow;
int Out=0;
for (int i=cur[u];i;i=e[i].nxt){
if (!Flow) break;
cur[u]=i;
int v=e[i].to;
if (e[i].f&&dep[v]==dep[u]+1){
int tmp=dfs(v,min(Flow,e[i].f));
e[i].f-=tmp,e[i^1].f+=tmp,Flow-=tmp,Out+=tmp;
}
}
return Out;
}
void printans(){
printf("%lld\n",ans);
for (int i=1;i<=n;i++){
int x=dep[L[i]],y=dep[R[i]];
if (x==y) putchar('C');
else if (x) putchar('A');
else putchar('B');
}
}
signed main(){
n=read(),m=read(),x=read(),y=read();
for (int i=1;i<=n;i++) L[i]=(++T),R[i]=(++T);
T++;
while (m--){
int u=read(),v=read(),w=read();
Add_bir(L[u],R[v],w),Add_bir(L[v],R[u],w);
}
Add_bir(S,L[x],inf),Add_bir(R[x],T,inf);
Add_bir(S,R[y],inf),Add_bir(L[y],T,inf);
while (bfs()) ans+=dfs(S,inf);
return printans(),0;
}
标签:Kingdom,连通,ch,SS,题解,TT,Partition,TS,ST
From: https://www.cnblogs.com/ducati/p/17093045.html