HDU_3667_Transportation(最小费用流)
2015-09-23 00:37
483 查看
Transportation
[b]Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2477 Accepted Submission(s): 1059
[/b]
Problem Description
There are N cities, and M directed roads connecting them. Now you want to transport K units of goods from city 1 to city N. There are many robbers on the road, so you must be very careful. The more goods you carry, the more dangerous
it is. To be more specific, for each road i, there is a coefficient ai. If you want to carry x units of goods along this road, you should pay ai * x2
dollars to hire guards to protect your goods. And what’s worse, for each road i, there is an upper bound Ci, which means that you cannot transport more than Ci units
of goods along this road. Please note you can only carry integral unit of goods along each road.
You should find out the minimum cost to transport all the goods safely.
Input
There are several test cases. The first line of each case contains three integers, N, M and K. (1 <= N <= 100, 1 <= M <= 5000, 0 <= K <= 100). Then M lines followed, each contains four integers (ui,
vi, ai, Ci), indicating there is a directed road from city ui to vi,
whose coefficient is ai and upper bound is Ci. (1 <= ui, vi <= N, 0
< ai <= 100, Ci <= 5)
Output
Output one line for each test case, indicating the minimum cost. If it is impossible to transport all the K units of goods, output -1.
Sample Input
2 1 2 1 2 1 2 2 1 2 1 2 1 1 2 2 2 1 2 1 2 1 2 2 2
Sample Output
4 -1 3
题意:求从城市1运送K单位物品到城市n的最小花费。给定的有向边,每条边都有其容量c,并且,产生的费用是 a * ( f * f ),其中f是这条边上的流量,a是给出的系数。
分析:这个题貌似是刘汝佳大白书当作一种典型的建图方法:拆边法。假如给定一条边(u,v),其计费系数为a,容量为c,那么可以把(u,v)拆成5条边,费用为(1a,3a,5a,7a,9a),容量都为1,为何这样子建图是有效的呢?很明显,假设流量为1,根据最短路优先原则那么肯定走的是cost=1a的那条边;若流量为2,肯定走的是cost=(1a,3a)的两条边;若流量为3,肯定走的是cost=(1a,3a,5a)三条边;若流量为4,那么则走cost=(1a,3a,5a,7a)四条边;若流量为5,那么走(1a,3a,5a,7a,9a)五条边。对所有输入的有向边,按照上述方法拆边建图,然后加入超级源点s(0),s连向1,容量为K,费用为0。然后跑一遍最小费用最大流,若流量不等于K,则输出-1,否则输出最小费用。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667
代码清单:
#include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<ctime> #include<cctype> #include<string> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; #define end() return 0 typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; const int maxn = 100 + 5; const int INF = 0x7f7f7f7f; struct Edge{ int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){} }; struct MCMF{ int n,m,flow,cost; vector<Edge>edge; //边数的两倍 vector<int>G[maxn]; //邻接表,G[i][j]表示i的第j条边在e数组中的序号 int inq[maxn]; //是否在队列 int d[maxn]; //Bellman-Ford int p[maxn]; //上一条弧 int a[maxn]; //可改进量 void init(int n){ this -> n = n; for(int i=0;i<=n;i++) G[i].clear(); edge.clear(); } void addEdge(int from,int to,int cap,int cost){ edge.push_back(Edge(from,to,cap,0,cost)); edge.push_back(Edge(to,from,0,0,-cost)); m=edge.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,int& flow,int& cost){ memset(d,INF,sizeof(d)); memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); inq[u]=0; for(int i=0;i<G[u].size();i++){ Edge& e=edge[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){ q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INF) return false; flow+=a[t]; cost+=d[t]*a[t]; for(int u=t;u!=s;u=edge[p[u]].from){ edge[p[u]].flow+=a[t]; edge[p[u]^1].flow-=a[t]; } return true; } //需要保证初始网络中没有负权圈 void MincostMaxflow(int s,int t){ flow=0,cost=0; while(BellmanFord(s,t,flow,cost)); } }; struct EDGE{ int u,v,a,c; EDGE(){} EDGE(int u,int v,int a,int c):u(u),v(v),a(a),c(c){} }; int N,M,K; int u,v,a,c; EDGE edges[5005]; MCMF mcmf; void input(){ for(int i=1;i<=M;i++){ scanf("%d%d%d%d",&u,&v,&a,&c); edges[i]=EDGE(u,v,a,c); } } void createGraph(){ mcmf.init(N+1); mcmf.addEdge(0,1,K,0); for(int k=1;k<=M;k++){ int x=edges[k].c*edges[k].c; for(int i=1,j=1;j<=x;i+=2,j+=i){ mcmf.addEdge(edges[k].u,edges[k].v,1,edges[k].a*i); } } } void solve(){ createGraph(); mcmf.MincostMaxflow(0,N); if(mcmf.flow==K) printf("%d\n",mcmf.cost); else printf("-1\n"); } int main(){ while(scanf("%d%d%d",&N,&M,&K)!=EOF){ input(); solve(); }end(); }
相关文章推荐
- JavaScript----数字转换字符串&字符串转发数字
- (奶油小刀插件) android-butterknife-zelezny 插件使用
- Android 网络编程
- CentOS 6 使用 yum 安装MongoDB及服务器端配置
- spfa算法
- 自定义的一个分页类
- 【UIKit-124-3】#import <UIKit/UIView.h>
- Acdream 1667 调皮的数一 (ACdreamer java 专场)
- HDU1231最大连续子序列(动态规划)
- 对称加密和非对称加密
- codechef Tree and Queries Solved
- 软工个人项目
- VS2010 Qt5开发实用技能
- POJ 1010 STAMPS(DFS)
- 如何判断一个字符串中的括号是否匹配
- ios archives 出现的是other items而不是iOS Apps的解决方案
- Director类源代码不完全分析
- 任务推送系统的设计思路
- 操作系统页面置换算法(opt,lru,fifo,clock)实现
- css3动画图片变形,自定义字体