bzoj1834 [ZJOI2010]network 网络扩容
2016-04-15 10:19
549 查看
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
HINT
Source
Day1
第一问很简单,按数据建图,然后一遍最大流算法即可。
第二问则需要用最小费用最大流算法,主要是建图,那么可以从第一问的残留网络上继续建图,对残留网络上的每一条边建一条容量是∞费用是w的边(反向弧容量为0,费用为-w),然后建一个超级源点,从超级源向1建一条容量为k,费用为0的边,对这个图进行最小费用最大流算法。
最小费用最大流操作:
1.首先要对于这道题的图来说,有的边需要花费费用,而有的又不用,而不用扩容的边费用为0,需要扩容的边费用为w,容量无限,这就是本题这样建图的原因。
2.对于残留网络进行费用最短路SPFA算法,不用扩容的边一定会选费用为0的边,然后记录路径,找最小容量对可行路进行增流,更新ans
粘自黄学长。
给定一张有向图,每条边都有一个容量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
Day1
第一问很简单,按数据建图,然后一遍最大流算法即可。
第二问则需要用最小费用最大流算法,主要是建图,那么可以从第一问的残留网络上继续建图,对残留网络上的每一条边建一条容量是∞费用是w的边(反向弧容量为0,费用为-w),然后建一个超级源点,从超级源向1建一条容量为k,费用为0的边,对这个图进行最小费用最大流算法。
最小费用最大流操作:
1.首先要对于这道题的图来说,有的边需要花费费用,而有的又不用,而不用扩容的边费用为0,需要扩容的边费用为w,容量无限,这就是本题这样建图的原因。
2.对于残留网络进行费用最短路SPFA算法,不用扩容的边一定会选费用为0的边,然后记录路径,找最小容量对可行路进行增流,更新ans
粘自黄学长。
#include<iostream> #include<cstdio> #include<cstring> #define inf 0x7fffffff using namespace std; int n,m,k,cnt=1,ans,head[1001],from[1001],q[1001],h[1001],dis[1001]; bool inq[1001]; struct data{int from,to,v,c,next,t;}e[50001]; void ins(int u,int v,int w,int c) { cnt ++; e[cnt].to = v; e[cnt].from = u; e[cnt].v = w; e[cnt].t = c; e[cnt].next = head[u]; head[u] = cnt; } void insert(int u,int v,int w,int c) { ins(u,v,w,c); ins(v,u,0,-c); } void ins2(int u,int v,int w,int c) { cnt ++; e[cnt].to = v; e[cnt].from=u; e[cnt].v=w;e[cnt].c=c; e[cnt].next=head[u];head[u]=cnt; } void insert2(int u,int v,int w,int c) {ins2(u,v,w,c);ins2(v,u,0,-c);} void build() { int t=cnt; for(int i=2;i<=t;i+=2) if(i%2==0)insert2(e[i].from,e[i].to,inf,e[i].t); } bool bfs() { int t=0,w=1,i,now; memset(h,-1,sizeof(h)); q[0]=1;h[1]=0; while(t!=w) { now=q[t];t++;if(t==1000)t=0;i=head[now]; while(i) { if(e[i].v&&h[e[i].to]==-1) { h[e[i].to]=h[now]+1; q[w++]=e[i].to;if(w==1000)w=0; } i=e[i].next; } } if(h ==-1)return 0; return 1; } int dfs(int x,int f) { if(x==n)return f; int i=head[x],w,used=0; while(i) { if(e[i].v>0&&h[e[i].to]==h[x]+1) { w=f-used; w=dfs(e[i].to,min(w,e[i].v)); e[i].v-=w; e[i^1].v+=w; used+=w; if(used==f)return f; } i=e[i].next; } if(!used)h[x]=-1; return used; } void dinic(){while(bfs())ans+=dfs(1,inf);} bool spfa() { int t=0,w=1,i,now; for(int i=0;i<=n;i++)dis[i]=inf; q[0]=dis[0]=0;inq[0]=1; while(t!=w) { now=q[t];t++;i=head[now]; if(t==n)t=0; while(i) { if(e[i].v>0&&dis[now]+e[i].c<dis[e[i].to]) { dis[e[i].to]=dis[now]+e[i].c; from[e[i].to]=i; if(!inq[e[i].to]) {q[w++]=e[i].to;if(w==n)w=0;inq[e[i].to]=1;} } i=e[i].next; } inq[now] = 0; } if(dis == inf)return 0; return 1; } void mcf() { int i,x = inf; i = from ; while(i) { x = min(x,e[i].v); i = from[e[i].from]; } i = from ; while(i) { e[i].v -= x; e[i^1].v += x; ans += x * e[i].c; i = from[e[i].from]; } } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) { int u,v,w,c; scanf("%d%d%d%d",&u,&v,&w,&c); insert(u,v,w,c); } dinic(); printf("%d ",ans); ans=0;build(); ins(0,1,k,0); while(spfa())mcf(); printf("%d",ans); return 0; }
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- C语言实现选择排序、冒泡排序和快速排序的代码示例
- 探讨C语言的那些小秘密之断言
- C语言实现BMP转换JPG的方法
- 深入探讨C语言中局部变量与全局变量在内存中的存放位置