费用流——网络流板子
今天学了一种网络流,叫费用流。就是把网络最大流的每一条边上加一个权值,然后在网络最大流中找一条权值最小的边。题意就是这样,但是操作起来好像不是很好做。
怎么办呢?其实就是找增广路的方法不一样,原来网络流通过bfs找增广路,这里我们通过spfa找增广路。怎么找呢?其实就是跑一遍·spfa,将最小的路径去掉然后再来一遍,那个最小的路径就是增广路。
代码实现有一定难度,我通过各种努力终于搞出来了(一开始快读错了。。。负数读的是错的。。。)
题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。 输入输出格式 输入格式: 第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。 接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。 输出格式: 一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。 输入输出样例 输入样例#1: 复制 4 5 4 3 4 2 30 2 4 3 20 3 2 3 20 1 2 1 30 9 1 3 40 5 输出样例#1: 复制 50 280
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define maxn 100010 template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(),c > '9' || c < '0') if(c == '-') op = 1; x = c - '0'; while(c = getchar(),c <= '9' && c >= '0') x = x * 10 + c - '0'; if(op == 1) x = -x; } bool vis[maxn]; int n,m,s,t,x,y,z,f,dis[maxn],pre[maxn],last[maxn],flow[maxn],maf,mic; //dis最小花费;pre每个点的前驱;last每个点的所连的前一条边;flow源点到此处的流量 struct Edge { int to,nxt,flow,dis;//flow流量 dis花费 } a[maxn]; int head[maxn],len; queue <int> q; void add(int from,int to,int flow,int dis) { a[++len].nxt=head[from]; a[len].to=to; a[len].flow=flow; a[len].dis=dis; head[from]=len; } bool spfa(int s,int t) { memset(dis,0x7f,sizeof(dis)); memset(flow,0x7f,sizeof(flow)); memset(vis,0,sizeof(vis)); q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1; while (!q.empty()) { int now=q.front(); q.pop(); vis[now]=0; for (int i=head[now]; i!=-1; i=a[i].nxt) { if (a[i].flow>0 && dis[a[i].to]>dis[now]+a[i].dis)//正边 { dis[a[i].to]=dis[now]+a[i].dis; pre[a[i].to]=now; last[a[i].to]=i; flow[a[i].to]=min(flow[now],a[i].flow);// if (!vis[a[i].to]) { vis[a[i].to]=1; q.push(a[i].to); } } } } return pre[t]!=-1; } void max_flow() { while (spfa(s,t)) { int now=t; maf+=flow[t]; mic+=flow[t]*dis[t]; while (now!=s) { a[last[now]].flow-=flow[t];//flow和dis容易搞混 a[last[now]^1].flow+=flow[t]; now=pre[now]; } } } int main() { memset(head,-1,sizeof(head)); len = -1; read(n);read(m);read(s);read(t); duke(i,1,m) { read(x);read(y);read(z);read(f); add(x,y,z,f); add(y,x,0,-f); } max_flow(); printf("%d %d\n",maf,mic); return 0; }
只想找一个不会伤害我的人