码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1834:最大流+最小费用最大流

时间:2016-01-15 23:06:36      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

为什么昨天看的时候就一直看不懂,果然智商是硬伤。。。然后今晚一看就懂了OrzOrz,关键是限制容量那个技巧。。。

--------------------------------------------------------------------------------------------

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define rep(i,n) for(int i=1;i<=n;i++)
#define clr(x,c) memset(x,c,sizeof(x))
const int inf=0x3f3f3f3f;
int read(){
 int x=0;char c=getchar();
 while(!isdigit(c))c=getchar();
 while(isdigit(c)){
  x=x*10+c-‘0‘;
  c=getchar();
 }
 return x;
}


struct edge{
 int to,cap,cost;
 edge *next,*rev;
};
edge e[20005],*pt=e,*cur[1005],*p[1005],*head[1005];
int d[1005],cnt[1005],inq[1005],a[1005];
void add(int u,int v,int d,int w){
 pt->to=v;pt->cap=d;pt->cost=w;pt->next=head[u];head[u]=pt++;
}
void adde(int u,int v,int d,int w){
 add(u,v,d,w);add(v,u,0,-w);
 head[u]->rev=head[v];
 head[v]->rev=head[u];
}
struct Edge{
 int from,to,cap,cost;
}edges[5005];


int maxflow(int s,int t,int n){
 clr(d,0);clr(cnt,0);cnt[0]=n;
 int flow=0,a=inf,x=s;
 while(d[s]<n){
  edge *ee;
  for(ee=cur[x];ee;ee=ee->next)
    if(ee->cap>0&&d[ee->to]+1==d[x]) break;
  if(ee){
   p[ee->to]=cur[x]=ee;
   a=min(a,ee->cap);
   x=ee->to;
   if(x==t){
    while(x!=s){
     p[x]->cap-=a;
     p[x]->rev->cap+=a;
     x=p[x]->rev->to;
    }
    flow+=a;
    a=inf;
   }
  }else{
   if(!--cnt[d[x]]) break;
   d[x]=n;
   for(ee=head[x];ee;ee=ee->next){
    if(ee->cap>0&&d[ee->to]+1<d[x]){
     d[x]=d[ee->to]+1;
     cur[x]=ee;
    }
   }
   cnt[d[x]]++;
   if(x!=s) x=p[x]->rev->to;
  }
 }
 return flow;
}


int mincost(int s,int t){
 int cost=0;
 while(1){
  clr(d,inf);clr(inq,0);
  d[s]=0;a[s]=inf;
  queue<int>q;q.push(s);inq[s]=1;
  while(!q.empty()){
   int x=q.front();q.pop();inq[x]=0;
   for(edge *ee=head[x];ee;ee=ee->next){
    if(ee->cap>0&&d[x]+ee->cost<d[ee->to]){
     d[ee->to]=d[x]+ee->cost;
     p[ee->to]=ee;
     a[ee->to]=min(a[x],ee->cap);
     if(!inq[ee->to]){
      q.push(ee->to);inq[ee->to]=1;
     }
    }
   }
  }
  if(d[t]==inf) break;
  cost+=a[t]*d[t];
  int x=t;
  while(x!=s){
   p[x]->cap-=a[t];
   p[x]->rev->cap+=a[t];
   x=p[x]->rev->to;
  }
 }
 return cost;
}


int main(){
 int n=read(),m=read(),k=read();
 rep(i,m){
  Edge &o=edges[i];
  o.from=read(),o.to=read(),o.cap=read(),o.cost=read();
  adde(o.from,o.to,o.cap,0);
 }
 int s=1,t=n;
 printf("%d ",maxflow(s,t,n));
 rep(i,m){
  Edge &o=edges[i];
  adde(o.from,o.to,inf,o.cost);
 }
 adde(0,s,k,0);adde(t,n+1,k,0);
 printf("%d\n",mincost(0,n+1));
 return 0;
}

--------------------------------------------------------------------------------------------

1834: [ZJOI2010]network 网络扩容

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 2262  Solved: 1129
[Submit][Status][Discuss]

Description

给定一张有向图,每条边都有一个容量C和一个扩容费用W。这里扩容费用是指将容量扩大1所需的费用。求: 1、 在不扩容的情况下,1到N的最大流; 2、 将1到N的最大流增加K所需的最小扩容费用。

Input

输入文件的第一行包含三个整数N,M,K,表示有向图的点数、边数以及所需要增加的流量。 接下来的M行每行包含四个整数u,v,C,W,表示一条从u到v,容量为C,扩容费用为W的边。

Output

输出文件一行包含两个整数,分别表示问题1和问题2的答案。

Sample Input

5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1

Sample Output

13 19
30%的数据中,N<=100
100%的数据中,N<=1000,M<=5000,K<=10

HINT

 

Source

[Submit][Status][Discuss]

bzoj1834:最大流+最小费用最大流

标签:

原文地址:http://www.cnblogs.com/fighting-to-the-end/p/5134500.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!