​​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 考虑简单的一条链的依赖,s−1−2−3−4−5−t

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

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

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

具体建模

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

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

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

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

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

一些解释

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

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

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

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

#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;
}
}