The 2021 Sichuan Provincial 四川省赛 F.Direction Setting(最小费用流)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The 2021 Sichuan Provincial 四川省赛 F.Direction Setting(最小费用流)相关的知识,希望对你有一定的参考价值。
给定 m m m条边,每个点有点权为 a i a_i ai
要求你为每条边定向,最小化
D = ∑ i = 1 n m a x ( 0 , d i − a i ) D=\\sum\\limits_{i=1}^nmax(0,d_i-a_i) D=i=1∑nmax(0,di−ai)
对于一条边 ( l , r ) (l,r) (l,r)要么指向 l l l要么指向 r r r
对于点 l l l来说,前 a i a_i ai条指向自己的边对 D D D没有任何贡献
从第 a i + 1 a_i+1 ai+1条边开始,每多一条边,权值增加 1 1 1
那么其实跑一个最小费用流就好了
因为对于每个点肯定是先走免费的 a i a_i ai条边再走收费边,符合权值的计算方式
具体连边
把第 i i i条边抽象为一个点 m i m_i mi,这条边连接着点 l i , r i l_i,r_i li,ri
源点 s s s连向每条边 m i m_i mi,流量为 1 1 1费用 0 0 0
m i m_i mi分别连向 l i , r i l_i,r_i li,ri,流量都是 1 1 1,费用都是 0 0 0
对于每个点 u u u, u u u连一条流量 a u a_u au费用 0 0 0的边到汇点,再连一条流量 i n f inf inf费用 1 1 1的边到汇点
跑一个最小费用最大流就是答案
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const int inf = 1e9;
int dis[maxn],vis[maxn],flow[maxn],pre[maxn],id[maxn];
int a[maxn],l[maxn],r[maxn];
int n,m,s,t;
struct edge
{
int to,nxt,flow,w;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow,int w)
{
d[++cnt] = ( edge ){v,head[u],flow,w},head[u] = cnt;
d[++cnt] = ( edge ){u,head[v],0,-w},head[v] = cnt;
}
bool spfa(int s,int t,int mx)
{
for(int i=0;i<=mx;i++) dis[i] = inf, vis[i] = 0;
queue<int>q; q.push( s );
dis[s] = 0, flow[s] = inf;
while( !q.empty() )
{
int u = q.front(); q.pop();
vis[u] = 0;
for(int i=head[u];i;i=d[i].nxt )
{
int v = d[i].to;
if( d[i].flow && dis[u]+d[i].w<dis[v] )
{
dis[v] = dis[u]+d[i].w, pre[v] = i;
flow[v] = min( d[i].flow,flow[u] );
if( !vis[v] ) q.push( v ), vis[v] = 1;
}
}
}
return dis[t]!=inf;
}
int MCMF(int s,int t,int mx)
{
int mincost = 0;
while( spfa(s,t,mx) )
{
mincost += dis[t]*flow[t];
int x = t, i;
while( x!=s )
{
i = pre[x];
d[i].flow -= flow[t], d[i^1].flow += flow[t];
x = d[i^1].to;
}
}
return mincost;
}
void build()
{
for(int i=1;i<=m;i++)
{
add(s,i,1,0);
id[i] = cnt+1; add(i,m+l[i],1,0); add(i,m+r[i],1,0);
}
for(int i=1;i<=n;i++)
add(m+i,t,a[i],0),add(m+i,t,inf,1);
}
int main()
{
int T; cin >> T;
while( T-- )
{
cin >> n >> m;
s = 0, t = n+m+1;
for(int i=1;i<=n;i++) scanf("%d",&a[i] );
for(int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i] );
build();
cout << MCMF(s,t,n+m+1) << endl;
for(int i=1;i<=m;i++)
printf("%d",d[id[i]].flow==0?1:0);
puts("");
cnt = 1;
for(int i=0;i<=t;i++) head[i] = 0;
}
}
以上是关于The 2021 Sichuan Provincial 四川省赛 F.Direction Setting(最小费用流)的主要内容,如果未能解决你的问题,请参考以下文章
The 2021 Sichuan Provincial 四川省赛 J - Ants(模拟+技巧)
The 2021 Sichuan Provincial 四川省赛 F.Direction Setting(最小费用流)
The 2021 Sichuan Provincial 四川省赛 E.Don‘t Really Like How The Story Ends(贪心dfs)