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做最小费用最大流
最终的费用为(网络流中计算的费用+原图中有费用的边的下界*这条边的费用)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 const int maxn=250; 9 const int minf=10000; 10 int n,m,S,T,SS,mx,ans; 11 struct nod{ 12 int x,y,v,co,rev,next; 13 }e[maxn*maxn]; 14 int head[maxn]={},tot=0; 15 int dis[maxn]={},fa[maxn]={},vis[maxn]={}; 16 inline void init(int x,int y,int v,int co){ 17 e[++tot].x=x;e[tot].y=y;e[tot].v=v;e[tot].co=co;e[tot].rev=tot+1;e[tot].next=head[x];head[x]=tot; 18 e[++tot].x=y;e[tot].y=x;e[tot].v=0;e[tot].co=-co;e[tot].rev=tot-1;e[tot].next=head[y];head[y]=tot; 19 } 20 queue<int>q; 21 inline bool SPFA(){ 22 memset(dis,31,sizeof(dis)); 23 memset(fa,0,sizeof(fa)); 24 mx=dis[0]; 25 q.push(S);dis[S]=0; 26 while(!q.empty()){ 27 int x=q.front();q.pop();vis[x]=0; 28 for(int i=head[x];i;i=e[i].next){ 29 int y=e[i].y; 30 if((!e[i].v)||dis[y]<=e[i].co+dis[x])continue; 31 dis[y]=e[i].co+dis[x];fa[y]=i; 32 if(!vis[y]){ 33 q.push(y);vis[y]=1; 34 } 35 } 36 } 37 return dis[T]!=mx; 38 } 39 inline void doit(){ 40 int val=mx; 41 for(int i=fa[T];i;i=fa[e[i].x])val=min(val,e[i].v); 42 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;} 43 } 44 int main(){ 45 int x; 46 scanf("%d%d",&n,&m);S=n*2+1;T=S+1;SS=T+1; 47 for(int i=1;i<=n;i++){ 48 scanf("%d",&x); 49 if(x<=0)continue; 50 init(i,i+n,0,0); 51 init(S,i+n,x,0); init(i,T,x,0); 52 } 53 for(int i=1;i<=n;i++){ 54 for(int j=i+1;j<=n;j++){ 55 scanf("%d",&x);if(x!=-1)init(i+n,j,minf,x); 56 } 57 } 58 init(S,SS,m,0); 59 for(int i=1;i<=n;i++) init(SS,i,minf,0); 60 ans=0; 61 while(SPFA())doit(); 62 printf("%d\n",ans); 63 return 0; 64 }