洛谷P2604 [ZJOI2010]网络扩容

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:  复制
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
输出样例#1:  复制
13 19

说明

30%的数据中,N<=100

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

第一问是裸的最大流,直接 Dinic。

第二问在第一问的残流网络上继续建图:对于数据中的m条边,再次建为容量INF,费用W[I]的边,最后再把0和1之间建上一条容量为k的边,用 SPFAMCMF 求0到n的最小费用流即可。

注:n应该<=5000

附代码:

#include
#include
#include
#include
#include
#define MAXN 5010
#define MAX 999999999
using namespace std;
int n,m,s,t,c=2,k,mincost=0;
int head[MAXN],path[MAXN],flow[MAXN],fa[MAXN],deep[MAXN];
bool vis[MAXN];
struct node1{
       int next,to,w,cost;
}a[MAXN<<2];
struct node2{
       int u,v,w,cost;
}b[MAXN];
inline int read(){
       int date=0,w=1;char c=0;
       while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
       while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
       return date*w;
}
void add(int u,int v,int w,int cost){
     a[c].to=v;a[c].w=w;a[c].cost=cost;
     a[c].next=head[u];
     head[u]=c++;
     a[c].to=u;a[c].w=0;a[c].cost=-cost;
     a[c].next=head[v];
     head[v]=c++;
}
bool bfs(){
     int u,v;
     queue q;
     memset(deep,0,sizeof(deep));
     deep[s]=1;
     q.push(s);
     while(!q.empty()){
                       u=q.front();
                       q.pop();
                       for(int i=head[u];i;i=a[i].next){
                               v=a[i].to;
                               if(a[i].w&&!deep[v]){
                                                    deep[v]=deep[u]+1;
                                                    if(v==t)return true;
                                                    q.push(v);
                                                    }
                               }
                       }
     return false;
}
int dfs(int x,int limit){
    if(x==t)return limit;
    int v,sum,cost=0;
    for(int i=head[x];i;i=a[i].next){
            v=a[i].to;
            if(a[i].w&&deep[v]==deep[x]+1){
                                           sum=dfs(v,min(limit-cost,a[i].w));
                                           if(sum>0){
                                                     a[i].w-=sum;
                                                     a[i^1].w+=sum;
                                                     cost+=sum;
                                                     if(limit==cost)break;
                                                     }
                                           else deep[v]=-1;
                                           }
            }
    return cost;
}
int dinic(){
    int ans=0;
    while(bfs())
    ans+=dfs(s,MAX);
    return ans;
}
bool spfa(){
     int u,v;
     queue q;
     for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;fa[i]=-1;deep[i]=0;}
     path[s]=0;
     vis[s]=true;
     fa[s]=0;
     flow[s]=MAX;
     q.push(s);
     while(!q.empty()){
                       u=q.front();
                       q.pop();
                       vis[u]=false;
                       for(int i=head[u];i;i=a[i].next){
                               v=a[i].to;
                               if(a[i].w&&path[v]>path[u]+a[i].cost){
                               path[v]=path[u]+a[i].cost;
                               deep[v]=i;
                               fa[v]=u;
                               flow[v]=min(flow[u],a[i].w);
                               if(!vis[v]){
                                           vis[v]=true;
                                           q.push(v);
                                           }
                               }
                               }
                       }
     if(path[t]!=MAX)return true;
     return false;
}
void EK(){
     while(spfa()){
                   for(int i=t;i!=s;i=fa[i]){
                           a[deep[i]].w-=flow[t];
                           a[deep[i]^1].w+=flow[t];
                           }
                   mincost+=flow[t]*path[t];
                   }
}
int main(){
    n=read();m=read();k=read();
    s=1;t=n;
    for(int i=1;i<=m;i++){
            b[i].u=read();b[i].v=read();b[i].w=read();b[i].cost=read();
            add(b[i].u,b[i].v,b[i].w,0);
            }
    printf("%d ",dinic());
    s=0;
    for(int i=1;i<=m;i++)add(b[i].u,b[i].v,MAX,b[i].cost);
    add(0,1,k,0);
    EK();
    printf("%d\n",mincost);
    return 0;
}

你可能感兴趣的:(网络流,最小费用最大流)