类型:最小费用流
题目:http://acm.hdu.edu.cn/showproblem.php?pid=3667
思路:对于每条边,不同流量的费用不同,可以将其拆边:对于容量为x的边,拆成x条容量为1的边,费用分别为1,3, 5,7....(2 * x - 1)。
第i次取该路时,费用为a * (2 * i - 1),此时流量为i,总费用为a * i ^ 2。求最小费用最大流。构造超级源点,流量为K,费用为0,用来判断解的存在性。
由于:n^2 = 1 + 3 + 5 + ... + (2 * n - 1)
// hdoj 3667 Transportation
// wa wa ac 468MS 872K
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
#define FOR(i,a,b) for(i = (a); i < (b); ++i)
#define FORE(i,a,b) for(i = (a); i <= (b); ++i)
#define FORD(i,a,b) for(i = (a); i > (b); --i)
#define FORDE(i,a,b) for(i = (a); i >= (b); --i)
#define CLR(a,b) memset(a,b,sizeof(a))
const int INF = 0x7f7f7f7f;
const int MAXN = 1010;
const int MAXM = 200000;
struct {
int v, cap, a, cost, nxt;
}edge[MAXM];
int n, m, ans, maxf, k, K;
int pre[MAXN], dis[MAXN], head[MAXN];
bool vis[MAXN];
void addedge(int u,int v, int ca, int co) {
edge[k].v = v;
edge[k].cap = ca;
edge[k].cost = co;
edge[k].nxt = head[u];
head[u] = k++;
edge[k].v = u;
edge[k].cap = 0;
edge[k].cost = -co;
edge[k].nxt = head[v];
head[v] = k++;
}
bool spfa(int x) {
int i;
FORE(i, 0, n + 1)
dis[i] = INF;
CLR(vis, false);
CLR(pre, 0);
dis[x] = 0;
queue<int> q;
q.push(x);
vis[x] = true;
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for(i = head[u]; i != -1; i = edge[i].nxt){
int v = edge[i].v;
if(edge[i].cap > 0 && dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]){
vis[v] = true;
q.push(v);
}
}
}
}
if(dis[n] == INF)
return false;
return true;
}
void end() {
int u, p, a = INF;
u = n;
while(u != 0) {
p = pre[u];
a = min(a, edge[p].cap);
u = edge[p ^ 1].v;
}
for(u = n; u != 0; u = edge[p ^ 1].v) {
p = pre[u];
edge[p].cap -= a;
edge[p ^ 1].cap += a;
}
ans += dis[n] * a;
maxf += a;
}
void init() {
int i, j;
int u, v, a, c;
k = 2;
maxf = ans = 0;
CLR(head, -1);
addedge(0, 1, K, 0);
FORE(i, 1, m) {
scanf("%d %d %d %d", &u, &v, &a, &c);
FORE(j, 1, c)
addedge(u, v, 1, a * (2 * j - 1));
}
}
int main() {
while(scanf("%d %d %d", &n, &m, &K) != EOF) {
init();
while(spfa(0)) {
end();
}
if(maxf < K)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}