HDU 3667 费用流 拆边 Transportation

题意:

有N个城市,M条有向道路,要从1号城市运送K个货物到N号城市。

每条有向道路<u, v>运送费用和运送量的平方成正比,系数为ai

而且每条路最多运送Ci个货物,求最小费用。

分析:

拆边,每条边拆成费用为a, 3a, 5a的边,这样就能保证每条边的费用和流量的平方成正比。

因为最多运送K个货物,所以增加一个源点和城市1连一条容量为K费用为0的边。

跑一边最小费用最大流,如果满流才有解。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 #include <vector>
  7 using namespace std;
  8
  9 const int maxn = 100 + 10;
 10 const int INF = 0x3f3f3f3f;
 11
 12 struct Edge
 13 {
 14     int from, to, cap, flow, cost;
 15     Edge(int u, int v, int cap, int flow, int cost):from(u), to(v), cap(cap), flow(flow), cost(cost) {}
 16 };
 17
 18 int n, s, t, m, k;
 19 vector<Edge> edges;
 20 vector<int> G[maxn];
 21
 22 void init(int n)
 23 {
 24     for(int i = 0; i < n; i++) G[i].clear();
 25     edges.clear();
 26 }
 27
 28 void AddEdge(int u, int v, int cap, int cost)
 29 {
 30     edges.push_back(Edge(u, v, cap, 0, cost));
 31     edges.push_back(Edge(v, u, 0, 0, -cost));
 32     int m = edges.size();
 33     G[u].push_back(m - 2);
 34     G[v].push_back(m - 1);
 35 }
 36
 37 bool inq[maxn];
 38 int p[maxn], d[maxn], a[maxn];
 39
 40 bool SPFA()
 41 {
 42     memset(d, 0x3f, sizeof(d));
 43     d[s] = 0;
 44     queue<int> Q;
 45     Q.push(s);
 46     memset(inq, false, sizeof(inq));
 47     inq[s] = true;
 48     memset(p, -1, sizeof(p));
 49     a[s] = INF;
 50
 51     while(!Q.empty())
 52     {
 53         int u = Q.front(); Q.pop(); inq[u] = false;
 54         for(int i = 0; i < G[u].size(); i++)
 55         {
 56             Edge& e = edges[G[u][i]];
 57             int v = e.to;
 58             if(e.cap > e.flow && d[u] + e.cost < d[v])
 59             {
 60                 d[v] = d[u] + e.cost;
 61                 p[v] = G[u][i];
 62                 a[v] = min(a[u], e.cap - e.flow);
 63                 if(!inq[v]) { inq[v] = true; Q.push(v); }
 64             }
 65         }
 66     }
 67
 68     return d[t] < INF;
 69 }
 70
 71 int Maxf;
 72
 73 int Mincost()
 74 {
 75     int cost = 0;
 76     Maxf = 0;
 77     while(SPFA())
 78     {
 79         Maxf += a[t];
 80         cost += a[t] * d[t];
 81         int u = t;
 82         while(u != s)
 83         {
 84             edges[p[u]].flow += a[t];
 85             edges[p[u]^1].flow -= a[t];
 86             u = edges[p[u]].from;
 87         }
 88     }
 89     return cost;
 90 }
 91
 92 int main()
 93 {
 94     while(scanf("%d%d%d", &n, &m, &k) == 3)
 95     {
 96         init(n + 1);
 97
 98         s = 0, t = n;
 99         AddEdge(s, 1, k, 0);
100
101         while(m--)
102         {
103             int u, v, a, C;
104             scanf("%d%d%d%d", &u, &v, &a, &C);
105             for(int i = 0; i < C; i++)
106                 AddEdge(u, v, 1, a * (i * 2 + 1));
107         }
108
109         int cost = Mincost();
110         if(Maxf < k) puts("-1");
111         else printf("%d\n", cost);
112     }
113
114     return 0;
115 }

代码君

时间: 2024-08-03 17:55:54

HDU 3667 费用流 拆边 Transportation的相关文章

HDU 3667 费用流(拆边)

题意:有n个城市(1~n),m条有向边:有k件货物要从1运到n,每条边最多能运c件货物,每条边有一个危险系数ai,经过这条路的费用需要ai*x2(x为货物的数量),问所有货物安全到达的费用. 思路:c<=5,这里可以做文章:把每条边拆成c条边,容量都为1,费用为ai*(2*i-1)(第二个i是指拆边时的第几条边).推导:x2-(x-1)2=2x-1. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #define min(x,y)

hdu 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

费用流 hdu3667 Transportation

传送门:点击打开链接 题意:n个节点m条有向边,每条有向边的容量是C,且费用是a*x^2,x是流量,问从1运送k流量到n的最小费用 一般做的费用流边的费用都是固定的,而这题并不是固定的. 但是,看到了C<=5,其实就是在提示可以拆边.. 假如C是3,我们就可以把一条边拆成3条边. 假如不拆,如果通过的流量是1,2,3,那么费用分别是a,4a,9a 如果拆成3条边,那么3条边的费用分别是a,3a,5a,容量都是1 这样就完美的解决了边的费用问题了~ #include<map> #inclu

Going Home HDU - 1533 (费用流)

Going Home HDU - 1533 1 //费用流初探 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #include <cstdio> 6 #include <algorithm> 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 110; 10 char gra

HDU 3376 费用流 Matrix Again

咳咳,内个,内什么,白书上的费用流模板没过,后来换了种存图方式才过. 题意: 给出一个n × n的矩阵,每个格子中有一个数字代表权值,找出从左上角出发到右下角的两条不相交的路径(起点和终点除外),使得两条路径权值之和最大. 分析: 如果n比较小的话是可以DP的,但是现在n非常大,DP会超时的. 这个用费用流来求解: 因为每个点只能走一次,所以先拆点,两点之间连一条容量为1费用为对应格子权值的边,如果是起点或终点,因为要走两次,所以要连容量为2的边. 对于不同格子之间,如果能到达,连一条容量为IN

hdu 5045 费用流

滚动建图,最大费用流(每次只有就10个点的二分图).复杂度,m/n*(n^2)(n<=10),今年网络赛唯一网络流题,被队友状压DP秒了....难道网络流要逐渐退出历史舞台???.... #include<iostream> //78ms #include<cstdio> #include<queue> using namespace std; const double inf =0x3f3f3f3f; const int maxv=50,maxe=500; in

hdu 4406 费用流

这题问题就是当前时刻到底选择哪门课程,易知选择是和分数有关的,并且是一个变化的权值,所以可以用拆点的方式,把从基础分到100分都拆成点,但若这样拆点的话,跑费用流时就必须保证顺序,这样就麻烦了..观察公式,发现同一门课,分数越高,权值是越低的,所以这是一个单调的,这样的话就可以对每一个分数建一条边,费用流会一条一条的跑. 注意将课程放在X集 #include<cstdio> #include<queue> #include<algorithm> #include<

HDU 5045 费用流求最大权

点击打开链接 题意:有n个人和m到题目,每个人做对的概率以矩阵形式给出,问如何分配才可以使做对的概率最大,有一个限制条件是做到目前为止每两个人的做题数量差距不能超过1,也就是前n道题目,必须一人做一个 思路:网上都是dp多一点,用网络流也可以,不过麻烦很多,可是本弱是一点dp都不会的选手啊,只能用网络流了,对于那个限制条件,我们可以以前n道题建一次图,然后再来n个,不过就直接建完就可以了,然后我们要求的是什么呢,很明显是最大权,而最大费用最大流刚好可以解决,这里面的费用流有两种方法,用spfa找

HDU 5644 (费用流)

Problem King's Pilots (HDU 5644) 题目大意 举办一次持续n天的飞行表演,第i天需要Pi个飞行员.共有m种休假计划,每个飞行员表演1次后,需要休假Si天,并提供Ti报酬来进行下一次表演.刚开始拥有k个飞行员.也可以招募飞行员来进行表演(数量无限),需要提供报酬q,在p天后参加表演.询问使表演顺利进行的最少花费,若无法进行,输出No solution. 解题分析 搬运官方题解: 稍微解释一下: 首先忽略Xi.Yi向T的流量表示第i天有多少人参加表演(第2条).S向Y1