(2020多校)H.Minimum-cost Flow(费用流的增广路)
发布日期:2021-06-30 10:20:34 浏览次数:3 分类:技术文章

本文共 2966 字,大约阅读时间需要 9 分钟。

这题没有考察建图,而是考察费用流的本质。

比如每次spfa只会找一条增广路

比如越先找到的增广路花费一定越小


首 先 发 现 容 量 为 u / v 是 没 办 法 算 的 ( 分 数 ) 首先发现容量为u/v是没办法算的(分数) u/v()

边 容 量 u / v , 最 大 流 是 1 边容量u/v,最大流是1 u/v,1

转 化 为 边 容 量 u , 最 大 流 是 v ( 这 样 花 费 最 后 要 除 以 v ) 转化为边容量u,最大流是v(这样花费最后要除以v) u,v(v)

面 对 这 么 多 询 问 , 我 们 预 处 理 一 下 每 条 增 广 路 的 花 费 就 行 了 面对这么多询问,我们预处理一下每条增广路的花费就行了 ,广

按 题 目 建 图 , 流 量 暂 时 设 置 为 1 , 因 为 好 算 按题目建图,流量暂时设置为1,因为好算 ,1,

每 次 s p f a 后 , 到 t 的 流 量 一 定 是 1 , 所 以 只 需 要 记 录 每 条 增 广 路 的 花 费 在 p a t h 数 组 每次spfa后,到t的流量一定是1,所以只需要记录每条增广路的花费在path数组 spfa,t1,广path

那 么 现 在 每 个 询 问 里 边 容 量 是 u , 最 大 流 是 v 那么现在每个询问里边容量是u,最大流是v u,v

设 v = a u + b   ( b < u ) 设v=au+b\ (b<u) v=au+b (b<u)

因 为 每 条 边 的 容 量 是 u , 所 以 至 少 需 要 a 条 增 广 路 因为每条边的容量是u,所以至少需要a条增广路 u,a广

如 果 b 不 为 0 , 那 么 第 a + 1 条 增 广 路 需 要 走 b u 如果b不为0,那么第a+1条增广路需要走\frac{b}{u} b0,a+1广ub

所 以 设 s u m n 是 p a t h 的 前 缀 和 数 组 所以设sumn是path的前缀和数组 sumnpath

花 费 是 s u m n [ x ] + p a t h [ x + 1 ] ∗ b / u 花费是sumn[x]+path[x+1]*b/u sumn[x]+path[x+1]b/u

但是不要忘记sumn是容量为1的花费

现在容量是u,那么还需要乘以u

所 以 花 费 是 s u m n [ x ] ∗ u + p a t h [ x + 1 ] ∗ b 所以花费是sumn[x]*u+path[x+1]*b sumn[x]u+path[x+1]b

再 除 以 v 就 好 啦 ! 因 为 1 到 n 只 需 要 1 的 流 量 而 不 是 v 的 流 量 再除以v就好啦!因为1到n只需要1的流量而不是v的流量 v!1n1v

#include 
using namespace std;#define int long longconst int maxn=2e5+10;const int inf=1e9;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;}int dis[maxn],vis[maxn],top,path[maxn],sumn[maxn],flow[maxn],pre[maxn];bool spfa(){ for(int i=0;i<=t;i++) dis[i]=inf,vis[i]=0; dis[s]=0; flow[s]=inf; queue
q; q.push( s ); 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[v]>dis[u]+d[i].w ) { dis[v]=dis[u]+d[i].w; flow[v]=min( flow[u],d[i].flow ); pre[v]=i; if( !vis[v] ) vis[v]=1,q.push( v ); } } } return dis[t]!=inf;}void dinic(){ while( spfa() ) { int x=t; path[++top]=dis[t]; //第top条增广路的花费,流量一定是1,所以没乘flow[t] while( x!=s ) { int i=pre[x]; d[i].flow-=1; d[i^1].flow+=1; x=d[i^1].to; } }}int gcd(int a,int b){ return b==0?a:gcd(b,a%b);}signed main(){ while( cin >> n >> m ) { for(int i=1;i<=m;i++ ) { int l,r,w; scanf("%lld%lld%lld",&l,&r,&w); add(l,r,1,w); } s=1,t=n; dinic(); for(int i=1;i<=top;i++) sumn[i]=sumn[i-1]+path[i]; int q; cin >> q; while( q-- ) { int u,v; scanf("%lld%lld",&u,&v); if( u==0 ) { cout << "NaN\n"; continue; } int x=v/u,y=v%u; if( x>top || ((x+1)>top&&y) ) cout << "NaN\n"; else { int cost=sumn[x]*u+path[x+1]*y; int yin=gcd(cost,v); printf("%lld/%lld\n",cost/yin,v/yin); } } for(int i=1;i<=n;i++) head[i]=0; cnt=1,top=0; }}

转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/108181087 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:n^3的KM完美匹配算法(bfs迭代版本)
下一篇:P2057 [SHOI2007]善意的投票 / [JLOI2010]冠军调查

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月21日 11时43分34秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章