网络流-费用流

这个好像不考

没事可以骗分

费用流,顾名思义,就是有费用的流,也就是说,给一个网络流图中的每条弧增加一个单位流量费用。

一般来说求解的费用流都是最大流最小费用。

好像没什么好BB的

这里推荐使用zkw算法求解最小费用流,看着代码理解就行,应该还是很好理解的。

(zkw算法在稠密图上跑得飞快,在稀疏图上还不如直接SPFA)

#include <bits/stdc++.h>
using namespace std;

const int max_l = 1000005;
const int maxdelta = 2e9;

struct hazaking
{
	int y, next, v, c;
}e[max_l];//c表示这条边的单位流量费用
int linkk[max_l];
int t = 1;

int dis[max_l], delta[max_l], q[max_l*10], p[max_l];
bool vis[max_l];

long long ans = 0;

inline void insert(int x,int y,int z,int c)
{
	e[++t].next = linkk[x];
	e[t].y = y;
	e[t].v = z;
	e[t].c = c;
	linkk[x] = t;
	e[++t].next = linkk[y];
	e[t].y = x;
	e[t].v = 0;
	e[t].c = -c;//反向边为负费用
	linkk[y] = t;
}

inline int read()
{
	int sum = 0, flag = 1;
	char c = getchar();
	for (; c < '0' || c > '9' ; c = getchar())
	 if (c == '-') flag = -1;
	for (; c >= '0' && c <= '9'; c = getchar())
	 sum = (sum << 3) + (sum << 1) + c - 48;
	return sum * flag;
}

int n = read(), m = read();

inline bool spfa()
{
	memset(vis, false, sizeof(vis));
	for (int i = 1; i < n; i++)
	 dis[i] = int (2e9);//初始化dis数组
	dis[n] = 0;
	vis[n] = true;
	q[1] = n;//这里的SPFA是需要倒着跑的
	int qh = 1, qt = 1;
	while (qh <= qt)
	 {
	 	for (int i = linkk[q[qh]]; i ; i = e[i].next )
	 	 if (e[i^1].v && dis[e[i].y] > dis[q[qh]] - e[i].c )//由于是倒着跑,需要修改一下if
	 	  {
	 	  	dis[e[i].y] = dis[q[qh]] - e[i].c;//修改dis
	 	  	if (!vis[e[i].y])
	 	  	 {
	 	  	 	vis[e[i].y] = true;
	 	  	 	q[++qt] = e[i].y;//入队
	 	  	 }
	 	  }
	 	vis[ q[qh++] ] = false;
	 }
	return dis[1] != int (2e9);
}

int dfs(int k,int delta)
{
	vis[k] = true;
	if (k == n) return delta;
	int ma = 0, add;
	for (int i = linkk[k]; i && ma < delta; i = e[i].next)
	 if (!vis[e[i].y] && e[i].v && dis[e[i].y] == dis[k] - e[i].c)
	  {
	  	if (add = dfs(e[i].y, min(e[i].v, delta - ma))) 
	  	 {
	  	 	ans += add * e[i].c;//给最小费用加上费用,由于c是单位流量费用,这里要乘起来
	  	 	e[i].v -= add;
	  	 	e[i ^ 1].v += add;
	  	 	ma += add;
	  	 }
	  }
	return ma;
}

inline int costflow()
{
	int ans=0;
	while (spfa())
	 {
	 	vis[n] = true;
	 	while (vis[n])
	 	 {
	 	 	memset(vis, false, sizeof(vis));
	 	 	ans+=dfs(1, maxdelta);
	 	 }
	 }
	return ans;
}

inline void init()
{
	for (int i = 1; i <= m; i++)
	 {
	 	int x = read(), y = read(), z = read(), c = read();
	 	insert(x, y, z, c);
	 }
}

inline void work()
{
	printf("%d ",costflow());//求解最大流
	printf("%lld\n",ans);//ans为最小费用
}

int main()
{
	init();
	work();
}


猜你喜欢

转载自blog.csdn.net/fsl123fsl/article/details/80487541