最小费用最大流模版

来源:互联网 发布:迅龙数据恢复下载安装 编辑:程序博客网 时间:2024/05/17 04:36
#include <cstdio>#include <algorithm>#include <cstring>//思路 : 不断找最短路, 直到不能增广了则为最小费用最大流 using namespace std;int n, m, s, t;struct node{int a, b, c, n, v;}d[200001];int h[10001];int v[10001];//费用 int w[10001];//容量 int u[10001];int que[100001];int pre[10001];//前导边int bian[100001];int ans; int read(){int x, f = 1;char ch;while(ch = getchar(), ch<'0'||ch>'9') if(ch == '-') f = -1;x = ch - 48;while(ch = getchar(), '0'<=ch&&ch<='9') x = x * 10 + ch - 48;return x * f;}void cr(int cnt, int a, int b, int c, int v){d[cnt].a = a; d[cnt].b = b; d[cnt].c = c; d[cnt].v = v; d[cnt].n = h[a];h[a] = cnt;}int cmp(int i, int j){ return d[i].v<d[j].v;} void bfs(){memset(w,0,sizeof(v));memset(v,1,sizeof(v));memset(pre,0,sizeof(pre));w[s] = 1e9; v[s] = 0;int x, y, i, b, c, va, a, j;que[x = y = 1] = s;  while(x <= y){a = que[x++];u[a] = 0; for(j = h[a]; j < h[a+1]; j++){i = bian[j];//一条条排完序的边出来 b = d[i].b;c = d[i].c;va = d[i].v;if(c>0 && v[a]+va<v[b]){//费用小才入队 v[b] = v[a] + va;pre[b] = i;w[b] = w[a]<c?w[a]:c;if(!u[b]){//spfa加sfl优化, 如果不在队列中,如果比目前对头的费用小就放在队头,不然放队尾, 可以减少入队 //可以 u[b] = 1;if(v[b]<v[que[x]] && x > 1) que[--x] = b;else que[++y] = b; }}}}for(i = pre[t]; i; i = pre[d[i].a]){d[i].c -= w[t];d[i^1].c += w[t];//正向边反向边更新 }}int main(){int i, j, a, b, c, x, a1 = 0, k;n = read(); m = read(); s = read(); t = read();for(i = 1; i <= m; i++){a = read(); b = read(); c = read(); x = read();cr(j=i*2,a,b,c,x);cr(j^1,b,a,0,-x);}for(k=i=1; i <= n; i++){//人为的边排序, 把每一条边放入bian[]中 for(j = h[i], h[i] = k; j; j = d[j].n){bian[k++] = j;} }h[n+1] = k;for(i = 1; i <= n; i++){if(h[i] < h[i+1]){sort(bian+h[i],bian+h[i+1],cmp);}}//权值小的边先出来,这样同一起点的边的终点可以不重复入队 while(1){bfs();if(w[t] > 0){a1 += w[t];ans += v[t] * w[t];}else break;}printf("%d %d", a1, ans);return 0;}


原创粉丝点击