BZOJ 3931: [CQOI2015]网络吞吐量【网络流】

题目分析:

似乎很明显的是个最大流问题
每个点有吞吐量限制,可以拆成两个点i和i+n,中间连一条容量为吞吐量的边
(注意1和n的吞吐量限制是 ∞ \infty
从n开始(或者1也可以)跑最短路得到dis数组,如果dis[u]==dis[v]+w[u][v] (具体方向根据代码而定),就从u+n向v连一条容量为inf的边
然后从1到n+n跑最大流。。。
然后。。。
在这里插入图片描述
我干了什么?
后来看了看,我把Dinic的bfs直接删掉了,因为最开始想已经求出最短路了就直接一次最大流dfs过去就好了呀。。。
然而,题目中的最短路并不是网络流中的最短路。。。所以dfs炸到飞起
加上bfs之后就过了。。
(这再一次告诉我们网络流的各种优化有多么重要。。。)
在这里插入图片描述
Code:

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define maxn 1005
#define maxm 200005
#define LL long long
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &a){
	char c;while(!isdigit(c=getc()));
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
const LL inf = 1ll<<60;
int n,m,S,T;
int fir[maxn],cur[maxn],dis[maxn],nxt[maxm],to[maxm],tot=1;
LL cap[maxm],d[maxn],w[maxn][maxn];
bool vis[maxn];
inline void line(int x,int y,LL z){
	nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y,cap[tot]=z;
	nxt[++tot]=fir[y],fir[y]=tot,to[tot]=x,cap[tot]=0;
}
void Dijkstra(int S)
{
	memset(d,0x3f,sizeof d);
	d[S]=0;
	for(int o=1;o<n;o++){
		int k=0;
		for(int i=1;i<=n;i++) if(!vis[i]&&d[i]<d[k]) k=i;
		vis[k]=1;
		for(int i=1;i<=n;i++) if(!vis[i]) d[i]=min(d[i],d[k]+w[i][k]);
	}
}
queue<int>q;
inline bool bfs()
{
	memset(dis,0,(T+1)<<2);
	dis[T]=1,q.push(T);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=fir[u];i;i=nxt[i]) if(cap[i^1]&&!dis[to[i]]){
			dis[to[i]]=dis[u]+1;
			q.push(to[i]);
		}
	}
	return dis[S];
}
inline LL dfs(int u,LL lim)
{
	if(u==T) return lim;
	LL need=lim,delta;
	for(int &i=cur[u];i;i=nxt[i]) if(cap[i]&&dis[u]==dis[to[i]]+1){
		delta=dfs(to[i],min(cap[i],need));
		cap[i]-=delta,cap[i^1]+=delta;
		if(!(need-=delta)) break;
	}
	return lim-need;
}
inline LL Dinic(){
	LL flow=0;
	while(bfs()) memcpy(cur,fir,(T+1)<<2),flow+=dfs(S,inf);
	return flow;
}
int main()
{
	freopen("H2O.in","r",stdin);
	int x,y;LL z;memset(w,0x3f,sizeof w);
	read(n),read(m);
	for(int i=1;i<=m;i++) read(x),read(y),read(z),w[x][y]=w[y][x]=min(w[x][y],z);
	Dijkstra(n);
	for(int i=1;i<=n;i++) read(z),line(i,i+n,i==1||i==n?inf:z);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(w[i][j]!=w[0][0]&&d[i]==d[j]+w[i][j]) line(i+n,j,inf);
	S=1,T=n+n;
	printf("%lld",Dinic());//一开始直接输出了dfs(S,inf),压根没有bfs
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值