ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【网络流】CF708D Incorrect Flow

2022-02-08 18:02:19  阅读:156  来源: 互联网

标签:Incorrect le CF708D int Flow 流量 vis ch dis


思考过程。无脑记录。

流量守恒:记 \(d(x)=in_x-out_x,d(x)=0\),因为上下界网络流经常这么表示,当然记 \(d(x)=out_x-in_x\) 也行。

减容量是可以舍弃的操作,因为减容量总是可以使用减流量解决或者会使其更不优。

再者,每条边给定的原始流量一定要先流满再说,所以上下界都是 \(f\)。

下面都省略了下界 0。

\(f \le c\),那么在不增加 \(c\) 的情况下,\(f\) 还能加 \(c-f\),考虑对 \(d(u),d(v)\) 的影响,假如加了 \(l\),那么 \(d(u)-=l,d(v)+=l\)。考虑这个式子如何建模吧。若原来的 \(d(x)>0,x\in [1,n]\) 说明入流多,要流出。对应的,对 \(d(x)<0\) 的,要流入,这部分有助于建模思考。考虑加 1,那么就是 \((u,v,c-f,1)\),即假如需要流经这条边,则会给 \(u\) 提供流出流量,给 \(v\) 提供流入流量。考虑减 1,那么就是对称的 \((v,u,f,1)\)。再考虑下当 \(f=c\) 的时候,这时候我们要增加流量的话,只能加容量再加流量,即花费 2。那么就是 \((u,v,+\infty,2)\)。

\(f>c\),欸,我不会,睡觉了。

考虑增加流量,那么先要增加 \(f-c\) 的容量(这东西我还没想明白咋建模,主要是这个花费应该只能后面跑完在算吧),且后面每次增加流量都要增加容量,即 \((u,v,+\infty,2)\)。减少流量,那么先要减少 \(f-c\) 的流量,再 \((v,u,c,1)\)。好像漏了些,不懂。。。

总算明白了,\(c\le f'\le f\) 也算一种情况,那么 \((f-f')+(f'-c)=f-c\),花费始终是 \(f-c\) 的,所以无论如何 \(f>c\) 的情况都有一个固定原始花费。那么这样子算减少流量,即 \((v,u,f-c,0)\),即最多可以减少这么多,因为只要保证 \(c\le f'\le f\) 即可。

#include <bits/stdc++.h>
#define int long long
#define inf (int)(2e15)
using namespace std;
int rd() {
    int f=1,sum=0; char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return sum*f;
}
#define N (int)(2e5+5)
struct edge {
	int nex,to,w,c;
}e[N<<1];
int chea[N],hea[N],d[N],cnt=1,n,m,ans,S,T,s,t;

void add_edge(int x,int y,int z,int c) {
	e[++cnt].nex=hea[x]; e[cnt].to=y; e[cnt].w=z; e[cnt].c=c; hea[x]=cnt;
}

void add(int x,int y,int z,int c) {
	add_edge(x,y,z,c); add_edge(y,x,0,-c);
}

void lradd(int x,int y,int l,int r,int c) {
	add(x,y,r-l,c); d[x]-=l; d[y]+=l;
}

namespace WLL {
	queue<int>q;
	int dis[N],S,T;
	bool vis[N];
	bool spfa() {
		for(int i=0;i<=T;i++) dis[i]=inf,vis[i]=0;
		dis[S]=0; q.push(S);
		while(!q.empty()) {
			int x=q.front(); q.pop();
			vis[x]=0;
			for(int i=hea[x];i;i=e[i].nex) {
				int y=e[i].to;
				if(e[i].w&&dis[y]>dis[x]+e[i].c) {
					dis[y]=dis[x]+e[i].c;
					if(!vis[y]) vis[y]=1,q.push(y);
				}
			}
		}
		return dis[T]<inf;
	}
	int dfs(int x,int lim) {
		if(x==T||!lim) return lim;
		int flow=0,fl;
		vis[x]=1;
		for(int i=hea[x];i&&lim;i=e[i].nex) {
			int y=e[i].to;
			if(e[i].w&&!vis[y]&&dis[y]==dis[x]+e[i].c) {
				fl=dfs(y,min(lim,e[i].w));
				if(!fl) continue;
				flow+=fl; lim-=fl; e[i].w-=fl; e[i^1].w+=fl;
				ans+=e[i].c*fl;
			}
		}
		if(!flow) dis[x]=inf;
		vis[x]=0;
		return flow; 
	}
	void zkw(int ss,int tt) {
		S=ss; T=tt;
		while(spfa()) {
			memset(vis,0,sizeof(int)*(T+2));
			dfs(S,inf);
		}
	}
}

signed main() {
	n=rd(); m=rd(); s=1; t=n; S=0; T=n+1;
	for(int i=1;i<=m;i++) {
		int x=rd(),y=rd(),c=rd(),f=rd();
		lradd(x,y,f,f,0);
		if(f<=c) {
			lradd(x,y,0,c-f,1);
			lradd(y,x,0,f,1);
			lradd(x,y,0,inf,2);
		} else {
			ans+=f-c;
			lradd(x,y,0,inf,2);
			lradd(y,x,0,c,1);
			lradd(y,x,0,f-c,0);
		}
	}
	lradd(t,s,0,inf,0);
	for(int i=1;i<=n;i++) {
		if(d[i]>0) add(S,i,d[i],0);
		else if(d[i]<0) add(i,T,-d[i],0);
	}
	WLL::zkw(S,T);
	printf("%lld",ans);
	return 0;
}

标签:Incorrect,le,CF708D,int,Flow,流量,vis,ch,dis
来源: https://www.cnblogs.com/xugangfan/p/15872282.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有