CF1666K Kingdom Partition 题解

神仙网络流题。

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;
}
posted @ 2023-02-05 11:02  ducati❤OI  阅读(69)  评论(0)    收藏  举报