任重而道远
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入输出格式
输入格式:第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。
接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。
AC代码:#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int M = 5e4 + 10;
const int N = 5e3 + 10;
const int INF = 1e9 + 7;
struct edge {
int tov, nxt, flw, val;
}e[M << 2];
int num = 1, src, sink, n ,m, maxflow = 0, mincost = 0;
int head[M << 1], dis[N], pree[N], prev[N];
bool vis[N];
void add_edge ( int u, int v, int w, int f ) {
num++;
e[num].tov = v;
e[num].nxt = head[u];
e[num].flw = f;
e[num].val = w;
head[u] = num;
num++;
e[num].tov = u;
e[num].nxt = head[v];
e[num].flw = 0;
e[num].val = -w;
head[v] = num;
}
bool spfa () {
memset (dis, 0x7f, sizeof (dis));
memset (vis, false, sizeof (vis));
queue <int> q;
q.push (src);
dis[src] = 0;
vis[src] = true;
while (!q.empty ()) {
int u = q.front ();
q.pop ();
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].tov;
if (e[i].flw && dis[u] + e[i].val < dis[v]) {
dis[v] = dis[u] + e[i].val;
pree[v] = i;
prev[v] = u;
if (!vis[v]) {
q.push (v);
vis[v] = true;
}
}
}
vis[u] = false;
}
return dis[sink] < dis[0];
}
void augment () {
int u = sink;
int delta = INF;
while (u != src) {
if (e[pree[u]].flw < delta)
delta = e[pree[u]].flw;
u = prev[u];
}
u = sink;
while (u != src) {
e[pree[u]].flw -= delta;
e[pree[u] ^ 1].flw += delta;
u = prev[u];
}
maxflow += delta;
mincost += delta * dis[sink];
}
int main () {
scanf ("%d%d%d%d", &n, &m, &src, &sink);
for (int i = 1; i <= m; i++) {
int u, v, w, f;
scanf ("%d%d%d%d", &u, &v, &w, &f);
add_edge (u, v, f, w);
}
while (spfa ())
augment ();
printf ("%d %d", maxflow, mincost);
return 0;
}