hdu 3667 Transportation(拆边费用流)
2013-11-04 21:18
274 查看
题目大意:要求从点1运输K件货物到点N,每对顶点间的费用为 a*x*x,其中x为该段路的流量,a为一个费用参数。求最小费用。
思路:题目明显是最小费用最大流问题,考虑到每段路的最大流量小于5,则可以将边拆开。比如s->e之间可以运输3件货物,那么将s->e拆成3条边(每条边视作不同的路),流量为1(只能走一次),假如单位费用为a,则该三条边的费用分别为a*1,a*3,a*5,假如该三条路都走了,就相当于直接从s到e运输三件货物,费用为a*3*3 = a*(1 + 3 + 5); 因为在该条路上运输2件货物这个问题上是包含了运输1件货物的,所以如果走了运输量为2件的这条路,潜意思就是运输量为1件的路也走了,所以当添加s->e且数量为2件的时候,费用应该为a*2*2-a*1*1
= 3*a,也就是 a*(n*n)-a*((n-1)*(n-1)) = 2*n - 1.
最后构造一个源点连接到起始点1上,费用为0,流量为K。
思路:题目明显是最小费用最大流问题,考虑到每段路的最大流量小于5,则可以将边拆开。比如s->e之间可以运输3件货物,那么将s->e拆成3条边(每条边视作不同的路),流量为1(只能走一次),假如单位费用为a,则该三条边的费用分别为a*1,a*3,a*5,假如该三条路都走了,就相当于直接从s到e运输三件货物,费用为a*3*3 = a*(1 + 3 + 5); 因为在该条路上运输2件货物这个问题上是包含了运输1件货物的,所以如果走了运输量为2件的这条路,潜意思就是运输量为1件的路也走了,所以当添加s->e且数量为2件的时候,费用应该为a*2*2-a*1*1
= 3*a,也就是 a*(n*n)-a*((n-1)*(n-1)) = 2*n - 1.
最后构造一个源点连接到起始点1上,费用为0,流量为K。
#include<cstdio> #include<cstring> #include<map> #include<vector> #include<cmath> #include<cstdlib> #include<stack> #include<queue> #include <iomanip> #include<iostream> #include<algorithm> using namespace std ; #define INF 0xfffffff #define MAX 105 struct node { int v,c,cost,next; }edge[MAX*1005]; int head[MAX]; int top; int N,M,K; int s,t,pt; int pre[MAX],pp[MAX]; int dis[MAX]; bool vist[MAX]; void add(int u,int v,int c,int cost) { edge[top].v = v; edge[top].c = c; edge[top].cost = cost; edge[top].next = head[u]; head[u] = top ++; edge[top].v = u; edge[top].c = 0; edge[top].cost = - cost; edge[top].next = head[v]; head[v] = top ++; } bool spfa() { queue <int> Q; memset(vist,false,sizeof(vist)); memset(pp,-1,sizeof(pp)); memset(pre,-1,sizeof(pre)); for(int i=0; i<=pt; i++) dis[i] = INF; dis[s] = 0; pre[s] = s; Q.push(s); vist[s] = true; while(!Q.empty()) { int cur = Q.front(); Q.pop(); vist[cur] = false; for(int i=head[cur]; i!=-1; i=edge[i].next) { int v = edge[i].v; if(edge[i].c > 0 && dis[v] > dis[cur] + edge[i].cost) { dis[v] = dis[cur] + edge[i].cost; pre[v] = cur; pp[v] = i; if(!vist[v]) { Q.push(v); vist[v] = true; } } } } if(dis[t] == INF) return false; return true; } int end() { int flow = 0,mincost = 0,minflow; while(spfa()) { minflow = INF; for(int i=t; i!=s; i=pre[i]) minflow = min(minflow,edge[pp[i]].c); flow += minflow; mincost += minflow*dis[t]; for(int i=t; i!=s; i=pre[i]) { edge[pp[i]].c -= minflow; edge[pp[i]^1].c += minflow; } } if(flow < K) return -1; return mincost; } int main() { while(~scanf("%d%d%d",&N,&M,&K)) { top = 0; memset(head,-1,sizeof(head)); for(int i=1; i<=M; i++) { int s,e,v,c; scanf("%d%d%d%d",&s,&e,&v,&c); for(int j=1; j<=c; j++) add(s,e,1,v*(2*j-1)); } s = 0; t = N+1; pt = N + 2; add(s,1,K,0); add(N,t,K,0); int ans = end(); printf("%d\n",ans); } return 0; }
相关文章推荐
- 黄淮学院CSDN高校俱乐部第一次HTML网页设计培训
- MyReport报表引擎2.7.6.0与MyReport.TD套打引擎1.0.5.0
- 【数据结构】 链表
- php中关于$this->a 与 $this->$a 的心得体会
- step-by-step多文件WEB批量上传(swfupload)的完美解决方案
- java之反射机制
- SQLServer资源及性能监控
- 【转】单链表判断是否有交点,是否有环
- duilib进阶教程 -- 总结 (17)
- Solr AutoSoftCommit
- 在MAC Pro上安装Windows8.1和2012R2
- 在MAC Pro上安装Windows8.1和2012R2
- 在MAC Pro上安装Windows8.1和2012R2
- Mybatis代码自动生成插件使用
- 第十周-求1000以内所有偶数的和(for语句)。
- Mybatis代码自动生成插件使用
- jquery选择器之属性过滤选择器
- oj整除和商的问题1104
- linux FrameBuffer
- jquery选择器之属性过滤选择器