15北京赛区Kejin Game(最小割思维)

tech2025-06-01  8

Kejin Game

首先在15年这是一道金牌题(可能现在不是了)

难点在于,没有明确的提示是网络流,想到网络流不一定想到最小割,想到最小割还有会建模

当然这个建模没有那么鬼畜,主要是思路历程要想对。


决 策 1 : 直 接 购 买 某 个 点 , 不 需 要 任 何 依 赖 \color{Red}决策1:直接购买某个点,不需要任何依赖 1:,

决 策 2 : 对 于 某 个 无 依 赖 的 点 , 可 以 直 接 购 买 \color{Red}决策2:对于某个无依赖的点,可以直接购买 2:,

决 策 3 : 对 于 某 条 依 赖 边 , 可 以 直 接 购 买 \color{Red}决策3:对于某条依赖边,可以直接购买 3:,

开始往费用流之类的方向想,都会遇到一个瓶颈

就是流无法解决多对一的关系(所有依赖边小时候才能执行决策2)

所以我们想到了最小割.

我 们 的 模 型 应 该 具 有 以 下 几 个 功 能 我们的模型应该具有以下几个功能

考 虑 简 单 的 一 条 链 的 依 赖 , s − 1 − 2 − 3 − 4 − 5 − t 考虑简单的一条链的依赖,s-1-2-3-4-5-t ,s12345t

假 如 我 们 对 5 使 用 决 策 1 , 那 么 s − t 应 该 直 接 断 掉 ( 满 足 最 小 割 ) 假如我们对5使用决策1,那么s-t应该直接断掉(满足最小割) 5使1,st()

假 如 我 们 对 4 使 用 决 策 1 , 那 么 [ 1 , 4 ] 应 该 都 不 考 虑 , 已 经 和 t 断 开 ( 一 个 割 ) 假如我们对4使用决策1,那么[1,4]应该都不考虑,已经和t断开(一个割) 4使1,[1,4],t()

但 是 仍 满 足 s − 4 − 5 − t 的 路 线 , 因 为 后 面 还 需 要 割 开 但是仍满足s-4-5-t的路线,因为后面还需要割开 s45t线,

具体建模

所 以 我 们 知 道 , 一 个 点 满 足 不 了 要 求 , 把 u 点 拆 为 u 和 u ′ 所以我们知道,一个点满足不了要求,把u点拆为u和u' ,,uuu

对 于 原 图 的 u − v 边 , 从 u ′ 向 v ′ 连 一 条 流 量 为 边 费 用 的 边 对于原图的u-v边,从u'向v'连一条流量为边费用的边 uv,uv

u 向 u ′ 连 一 条 流 量 为 决 策 1 的 边 u向u'连一条流量为决策1的边 uu1

s 向 u 连 一 条 流 量 为 决 策 2 的 边 s向u连一条流量为决策2的边 su2

跑 最 小 割 即 可 跑最小割即可

一些解释

由 于 对 于 一 个 点 u , 要 么 买 了 所 有 前 置 依 赖 边 , 要 么 直 接 决 策 一 购 买 这 个 点 由于对于一个点u,要么买了所有前置依赖边,要么直接决策一购买这个点 u,,

由 于 u − u ′ 有 决 策 1 的 边 , 割 掉 相 当 于 选 择 , 前 面 所 有 依 赖 边 相 当 于 都 割 掉 了 由于u-u'有决策1的边,割掉相当于选择,前面所有依赖边相当于都割掉了 uu1,,

又 因 为 有 s 到 u 为 决 策 2 的 边 , 如 果 割 掉 这 条 边 , 还 需 要 割 掉 所 有 到 u 的 依 赖 边 才 可 以 彻 底 割 掉 又因为有s到u为决策2的边,如果割掉这条边,还需要割掉所有到u的依赖边才可以彻底割掉 su2,,u

这 就 满 足 了 s 到 t 的 最 小 割 就 是 我 们 的 最 小 决 策 这就满足了s到t的最小割就是我们的最小决策 st

#include <bits/stdc++.h> using namespace std; const int maxn=2e5+10; const int inf=1e9; int n,m,s,t,dis[maxn],in[maxn]; struct edge{ int to,nxt,flow; }d[maxn]; int head[maxn],cnt=1; void add(int u,int v,int flow){ d[++cnt]=(edge){v,head[u],flow},head[u]=cnt; d[++cnt]=(edge){u,head[v],0},head[v]=cnt; } bool bfs() { for(int i=0;i<=t;i++) dis[i]=0; dis[s]=1; queue<int>q; q.push( s ); while( !q.empty() ) { int u=q.front(); q.pop(); for(int i=head[u];i;i=d[i].nxt ) { int v=d[i].to; if( d[i].flow&&dis[v]==0 ) { dis[v]=dis[u]+1; if( v==t ) return true; q.push( v ); } } } return false; } int dinic(int u,int flow) { if( u==t ) return flow; int res=flow; for(int i=head[u];i&&res;i=d[i].nxt ) { int v=d[i].to; if( dis[v]==dis[u]+1&&d[i].flow) { int temp=dinic(v,min(res,d[i].flow) ); if( temp==0 ) dis[v]=0; res-=temp; d[i].flow-=temp; d[i^1].flow+=temp; } } return flow-res; } signed main() { int T; cin >> T; while( T-- ) { int z; cin >> n >> m >> z; s=0,t=n*2+1; for(int i=1;i<=m;i++) { int l,r,w; cin >> l >> r >> w; add(l+n,r,w); } for(int i=1;i<=n;i++) { int x; cin >> x; add(s,i,x); } for(int i=1;i<=n;i++) { int x; cin >> x; add(i,i+n,x); } add(z+n,t,inf); int ans=0; while( bfs() ) ans+=dinic(s,inf); cout << ans << endl; cnt=1; for(int i=0;i<=t;i++) head[i]=0,in[i]=0; } }
最新回复(0)