题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667
解法:大白书366页,拆边法
SPFA代码(AC):
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <string.h>
#include <queue>
#include <sstream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string>
using namespace std;
const int MAXN = 10000;
const int MAXM = 200000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow, cost;
}edge[MAXM];
int head[MAXN], tol;
int pre[MAXN], dis[MAXN];
bool vis[MAXN];
int N;
void init(int n)
{
N = n;
tol = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
edge[tol].to = v;
edge[tol].cap = cap;
edge[tol].cost = cost;
edge[tol].flow = 0;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].to = u;
edge[tol].cap = 0;
edge[tol].cost = -cost;
edge[tol].flow = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
bool spfa(int s, int t)
{
queue<int>q;
for (int i = 0;i < N;i++)
{
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[s] = 0;
vis[s] = true;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;
for (int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > edge[i].flow &&
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 (pre[t] == -1)return false;
else return true;
}
int minCostMaxflow(int s, int t, int &cost)
{
int flow = 0;
cost = 0;
while (spfa(s, t))
{
int Min = INF;
for (int i = pre[t];i != -1;i = pre[edge[i ^ 1].to])
{
if (Min > edge[i].cap - edge[i].flow)
Min = edge[i].cap - edge[i].flow;
}
for (int i = pre[t];i != -1;i = pre[edge[i ^ 1].to])
{
edge[i].flow += Min;
edge[i ^ 1].flow -= Min;
cost += edge[i].cost*Min;
}
flow += Min;
}
return flow;
}
int n, m, k, ans;
int cnt[10] = { 0,1,3,5,7,9 };
int main()
{
while (~scanf("%d%d%d", &n, &m, &k))
{
init(n + 2);
addedge(0, 1, k, 0);
addedge(n, n + 1, k, 0);
int u, v, a, c;
for (int i = 1;i <= m;i++)
{
scanf("%d%d%d%d", &u, &v, &a, &c);
for (int j = 1;j <= c;j++)
addedge(u, v, 1, a*cnt[j]);
}
int tmp = minCostMaxflow(0, n + 1, ans);
if (ans < k) puts("-1");
else printf("%d\n", ans);
}
return 0;
}
zkw费用流代码(超时)(对二分图类型效率高):
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <string.h>
#include <queue>
#include <sstream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string>
using namespace std;
const int MAXN = 1000;
const int MAXM = 200000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to, next, cap, flow, cost;
Edge(int _to = 0, int _next = 0, int _cap = 0, int _flow = 0, int _cost = 0) :
to(_to), next(_next), cap(_cap), flow(_flow), cost(_cost) {}
}edge[MAXM];
struct ZKW_MinCostMaxFlow
{
int head[MAXN], tot;
int cur[MAXN];
int dis[MAXN];
bool vis[MAXN];
int ss, tt, N;//源点、汇点和点的总个数(编号是0~N-1),不需要额外赋值,调用会直接赋值
int min_cost, max_flow;
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int cap, int cost)
{
edge[tot] = Edge(v, head[u], cap, 0, cost);
head[u] = tot++;
edge[tot] = Edge(u, head[v], 0, 0, -cost);
head[v] = tot++;
}
int aug(int u, int flow)
{
if (u == tt)return flow;
vis[u] = true;
for (int i = cur[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap > edge[i].flow && !vis[v] && dis[u] == dis[v] + edge[i].cost)
{
int tmp = aug(v, min(flow, edge[i].cap - edge[i].flow));
edge[i].flow += tmp;
edge[i ^ 1].flow -= tmp;
cur[u] = i;
if (tmp)return tmp;
}
}
return 0;
}
bool modify_label()
{
int d = INF;
for (int u = 0;u < N;u++)
if (vis[u])
for (int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if (edge[i].cap>edge[i].flow && !vis[v])
d = min(d, dis[v] + edge[i].cost - dis[u]);
}
if (d == INF)return false;
for (int i = 0;i < N;i++)
if (vis[i])
{
vis[i] = false;
dis[i] += d;
}
return true;
}
/*
* 直接调用获取最小费用和最大流
* 输入: start-源点,end-汇点,n-点的总个数(编号从0开始)
* 返回值: pair<int,int> 第一个是最小费用,第二个是最大流
*/
pair<int, int> mincostmaxflow(int start, int end, int n)
{
ss = start, tt = end, N = n;
min_cost = max_flow = 0;
for (int i = 0;i < n;i++)dis[i] = 0;
while (1)
{
for (int i = 0;i < n;i++)cur[i] = head[i];
while (1)
{
for (int i = 0;i < n;i++)vis[i] = false;
int tmp = aug(ss, INF);
if (tmp == 0)break;
max_flow += tmp;
min_cost += tmp*dis[ss];
}
if (!modify_label())break;
}
return make_pair(min_cost, max_flow);
}
}solve;
int n, m, k;
int cnt[10] = { 0,1,3,5,7,9 };
int main()
{
while (~scanf("%d%d%d", &n, &m, &k))
{
solve.init();
solve.addedge(0, 1, k, 0);
solve.addedge(n, n + 1, k, 0);
int u, v, a, c;
for (int i = 1;i <= m;i++)
{
scanf("%d%d%d%d", &u, &v, &a, &c);
for (int j = 1;j <= c;j++)
solve.addedge(u, v, 1, a*cnt[j]);
}
pair<int, int> tmp = solve.mincostmaxflow(0, n + 1, n + 2);
int ans = tmp.second;
if (ans < k) puts("-1");
else printf("%d\n", tmp.first);
}
return 0;
}