【bzoj1834】[ZJOI2010]network 网络扩容

1834: [ZJOI2010]network 网络扩容

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 2701  Solved: 1368
[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
 
 
 
【题解】
网络流和费用流的结合。
第一问很简单,直接跑一遍dinic即可。
第二问是费用流,将原图上的每条边上建立一条附属边,流量为k,费用为扩容费用,然后跑费用流即可。
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<ctime>
  7 #include<algorithm>
  8 #include<queue>
  9 using namespace std;
 10 #define INF 1000000000
 11 #define MAXN 5010
 12 struct node{int x,y,next,v,c,rel;}e[MAXN*10],edge[MAXN*10];
 13 int n,m,k,len,ans,Link[MAXN],level[MAXN],vis[MAXN],dis[MAXN],lastnode[MAXN],lastedge[MAXN],q[MAXN*10];
 14 inline int read()
 15 {
 16     int x=0,f=1;  char ch=getchar();
 17     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
 18     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
 19     return x*f;
 20 }
 21 void insert(int x,int y,int v,int c)
 22 {
 23     e[++len].next=Link[x];Link[x]=len;e[len].x=x;e[len].y=y;e[len].v=v;e[len].c=c;e[len].rel=len+1;
 24     e[++len].next=Link[y];Link[y]=len;e[len].x=y;e[len].y=x;e[len].v=0;e[len].c=-c;e[len].rel=len-1;
 25 }
 26 bool bfs()
 27 {
 28     memset(level,-1,sizeof(level));
 29     int head=0,tail=1;  q[1]=1;  level[1]=0;
 30     while(++head<=tail)
 31         for(int i=Link[q[head]];i;i=e[i].next)
 32             if(level[e[i].y]<0&&e[i].v)
 33             {
 34                 q[++tail]=e[i].y;
 35                 level[q[tail]]=level[q[head]]+1;
 36             }
 37     return level[n]>=0;
 38 }
 39 int dinic(int x,int flow)
 40 {
 41     if(x==n) return flow;
 42     int maxflow=0,d=0;
 43     for(int i=Link[x];i&&maxflow<flow;i=e[i].next)
 44         if(level[e[i].y]==level[x]+1&&e[i].v)
 45             if(d=dinic(e[i].y,min(e[i].v,flow-maxflow)))
 46             {
 47                 maxflow+=d;
 48                 e[i].v-=d;
 49                 e[e[i].rel].v+=d;
 50             }
 51     if(!maxflow)  level[x]=-1;
 52     return maxflow;
 53 }
 54 void solve1()
 55 {
 56     int d=0;
 57     ans=0;
 58     while(bfs())
 59         while(d=dinic(1,INF))
 60             ans+=d;
 61     printf("%d ",ans);
 62 }
 63 bool spfa()
 64 {
 65     memset(vis,0,sizeof(vis));
 66     memset(dis,10,sizeof(dis));
 67     int head=0,tail=1,oo=dis[0];
 68     q[1]=1;  vis[1]=1;  dis[1]=0;
 69     while(++head<=tail)
 70     {
 71         int x=q[head];
 72         for(int i=Link[x];i;i=e[i].next)
 73             if(dis[x]+e[i].c<dis[e[i].y]&&e[i].v)
 74             {
 75                 dis[e[i].y]=dis[x]+e[i].c;
 76                 if(!vis[e[i].y])
 77                 {
 78                     q[++tail]=e[i].y;
 79                     vis[e[i].y]=1;
 80                 }
 81                 lastnode[e[i].y]=x;  lastedge[e[i].y]=i;
 82             }
 83         vis[x]=0;
 84     }
 85     return dis[n]<oo;
 86 }
 87 void cost()
 88 {
 89     int d=k;
 90     for(int i=n;i!=1;i=lastnode[i])
 91         if(e[lastedge[i]].v<d)
 92             d=e[lastedge[i]].v;
 93     for(int i=n;i!=1;i=lastnode[i])
 94     {
 95         int j=lastedge[i];
 96         e[j].v-=d;
 97         e[e[j].rel].v+=d;
 98         ans+=d*e[j].c;
 99     }
100     k-=d;
101 }
102 void solve2()
103 {
104     ans=0;
105     while(k)//控制1点的流量,相当于一个超级源的作用
106     {
107         spfa();
108         cost();
109     }
110     printf("%d\n",ans);
111 }
112 int main()
113 {
114     freopen("cin.in","r",stdin);
115     freopen("cout.out","w",stdout);
116     n=read();  m=read();  k=read();
117     for(int i=1;i<=m;i++)
118     {
119         int x=read(),y=read(),v=read(),c=read();
120         insert(x,y,v,0);
121         edge[i].x=x; edge[i].y=y; edge[i].c=c;
122     }
123     solve1();
124     for(int i=1;i<=m;i++)  insert(edge[i].x,edge[i].y,k,edge[i].c);
125     solve2();
126     return 0;
127 }

 

转载于:https://www.cnblogs.com/chty/p/5946545.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值