BZOJ2055 80人环游世界 网络流 费用流 有源汇有上下界的费用流

https://darkbzoj.cf/problem/2055

https://blog.csdn.net/Clove_unique/article/details/54864211 ←对有上下界费用流的处理方法

首先建立附加源汇ss,tt 
对于原图里有的一条边x->y,[l,r],cost,变成x->y,r-l,cost 
每一个点的权di定义为所有流入这个点的边的下界和-所有流出这个点的边的下界和 
对于一个点i,若di>0,ss->i,di,0;若di<0,i->tt,-di,0 
连边t->s,inf,0 
然后对ss,tt做最小费用最大流 
最终的费用为(网络流中计算的费用+原图中有费用的边的下界*这条边的费用)

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=;
const int minf=;
int n,m,S,T,SS,mx,ans;
struct nod{
int x,y,v,co,rev,next;
}e[maxn*maxn];
int head[maxn]={},tot=;
int dis[maxn]={},fa[maxn]={},vis[maxn]={};
inline void init(int x,int y,int v,int co){
e[++tot].x=x;e[tot].y=y;e[tot].v=v;e[tot].co=co;e[tot].rev=tot+;e[tot].next=head[x];head[x]=tot;
e[++tot].x=y;e[tot].y=x;e[tot].v=;e[tot].co=-co;e[tot].rev=tot-;e[tot].next=head[y];head[y]=tot;
}
queue<int>q;
inline bool SPFA(){
memset(dis,,sizeof(dis));
memset(fa,,sizeof(fa));
mx=dis[];
q.push(S);dis[S]=;
while(!q.empty()){
int x=q.front();q.pop();vis[x]=;
for(int i=head[x];i;i=e[i].next){
int y=e[i].y;
if((!e[i].v)||dis[y]<=e[i].co+dis[x])continue;
dis[y]=e[i].co+dis[x];fa[y]=i;
if(!vis[y]){
q.push(y);vis[y]=;
}
}
}
return dis[T]!=mx;
}
inline void doit(){
int val=mx;
for(int i=fa[T];i;i=fa[e[i].x])val=min(val,e[i].v);
for(int i=fa[T];i;i=fa[e[i].x]){e[i].v-=val; e[e[i].rev].v+=val; ans+=e[i].co*val;}
}
int main(){
int x;
scanf("%d%d",&n,&m);S=n*+;T=S+;SS=T+;
for(int i=;i<=n;i++){
scanf("%d",&x);
if(x<=)continue;
init(i,i+n,,);
init(S,i+n,x,); init(i,T,x,);
}
for(int i=;i<=n;i++){
for(int j=i+;j<=n;j++){
scanf("%d",&x);if(x!=-)init(i+n,j,minf,x);
}
}
init(S,SS,m,);
for(int i=;i<=n;i++) init(SS,i,minf,);
ans=;
while(SPFA())doit();
printf("%d\n",ans);
return ;
}
上一篇:some working learning总结学习


下一篇:[Git add . ] 遇到The file will have its original line endings in your working directory 解决办法