[SDOI2009]晨跑 费用流

本文深入解析了SDOI2009中的一道经典费用流题目,通过拆点技巧将问题转化为标准的费用流模型,并提供了一段完整的C++代码实现,展示了如何使用SPFA算法寻找增广路径并更新流量与费用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[SDOI2009]

  • BZOJ题面谁写的,出来挨打
  • 费用流垃圾套路题,拆点即可
#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
#define st(x) x
#define ed(x) x+n
#define ll long long
using namespace std;
const ll inf=1e9;
const ll N=1e6;
struct node{ll y,v,w,n;}e[N];
ll lin[N],flow[N/100],pre[N/100],v[N/100],d[N/100],S,T,len=1,x,y,w,n,m;
ll maxflow=0,ans=0;
void read(ll x,ll y,ll v,ll w)
{e[++len].y=y,e[len].v=v,e[len].w=w,e[len].n=lin[x],lin[x]=len;}
void add(ll x,ll y,ll v,ll w)
{read(x,y,v,w),read(y,x,0,-w);}

bool SPFA(){
	queue<ll> q;
	memset(v,0,sizeof(v));
	memset(d,0x3f,sizeof(d));
	q.push(S),v[S]=1,d[S]=0,flow[S]=inf;
	while(q.size()){
		ll x=q.front();q.pop();v[x]=0;
		for(ll i=lin[x];i;i=e[i].n){
			ll y=e[i].y;
			if(!e[i].v)continue;
			if(d[y]>d[x]+e[i].w){
				pre[y]=i;
				d[y]=d[x]+e[i].w;
				flow[y]=min(e[i].v,flow[x]);
				if(!v[y])v[y]=1,q.push(y);
			}
		}
	}return d[T]<inf;
}
void upd(){
	ll x=T;
	while(x!=S){
		ll i=pre[x];
		e[i].v-=flow[T];
		e[i^1].v+=flow[T];
		x=e[i^1].y;
	}
	maxflow+=flow[T];
	ans+=flow[T]*d[T];
}
int main()
{
	scanf("%lld%lld",&n,&m); S=ed(1),T=st(n);
	rep(i,1,n)add(st(i),ed(i),1,0);
	rep(i,1,m){
		scanf("%lld%lld%lld",&x,&y,&w);
		if(x==1&&y==n)add(ed(x),st(y),1,w);
		else add(ed(x),st(y),inf,w);
	}
	while(SPFA()) upd();
	cout<<maxflow<<" "<<ans;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值