前言:众所周知:spfa他死了

滑稽


dijkstra同样为最短路算法,为什么不能跑费用流qwq

好像是因为有负权边的缘故

但是如果我们如果使用某种玄学的将边权都拉回到正数的话

就可以跑了dijkstra,开心qwq


如果我们每条边暴力加上一个很大的值的话,我们还需要记录所经过的边数,还要保证不溢出,十分的毒瘤

尻考虑给每个节点一个势(ps:不是什么物理学算法,就是为了给他起个名字)

然后将我们的最短路转移\(dis_v=dis_u+w\)改为\(dis_v=dis_u+w+h_u-h_v\)(\(h_i\)是势),保证\(w+h_u-h_v>=0\)

然后我们观察蔡依林(雾他对最短路有什么影响

比如说我们现在有一条\(p_1-p_2-p_3.....p_n\)的这么一条路径

其路径长度则为\((w_1+w_2+w_3...+w_{n-1})+(h_1-h_2)+(h_2-h_3)+(h_3-h_4)+......(h_{n-1}-h_n)\)

然后发现这个玩意\(\to ~ (h_1-h_2)+(h_2-h_3)+(h_3-h_4)+......(h_{n-1}-h_n)=h_1-h_n\)。如此这样,我们在算出加势以后的(无论路线是什么样的)最短路后,在减去\(h_{begin}-h_{end}\)就可以了


接下来的问题就变成了,如何确定一个\(h_i\).

我们先考虑变形一下\(w+h_u-h_v>=0~~\to~~h_u+w>=h_v\)

\(wow\),好像三角形不等式呀(在最短路中对于一条从\(u\)到\(v\)的有向边,总有\(dis_u+w>=dix_v\))。

是不是可以考虑将上一次的\(dis\)当做\(h_i\)(每次\(h_i+=dis_i\))呢?

是可以的,为什么?

假设现在有一条\(u\to v\)的有向边

  • 假设他是一条权值是正的(不加势),那么肯定满足\(dis_u+w>=dis_v\)然就是最短路求错了。\(\therefore w+h_u-h_v>=0\)
  • 如果是一条权值是负的话,我们的\(h_i\)是累加的\(dis_i\)的,所以必定存在某一次增广,是的\(v \to u\)的边变到了\(u \to v\)

    然后这次增广(就是将\(v \to u\)的边反向的增广),肯定满足\(dis_v+w==dis_u(w>=0)~~~\to~~dis_v=dis_u-w\)

    然后这时的\(dis_u,dis_v\)已经被我们累加到了\(h_u,h_v\)中,然后我们继续变形\(dis_u-w-dis_v==0 ~~~\to~~ h_u-h_v-w>=0\)

    然后\(-w\)是\(u\to v\)这条边的权值。所以这次并不会成为负数

\(\mathcal{So}\)

我们这样的话就能跑dijkstra了。开心\(qwq\)

而且更快,更稳定,也不容易猝死


↓及其丑陋的代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
const int maxn=101000;
using std::swap;
using std::min;
struct Edge
{
int p;
int w;
int f;
int nxt;
};
struct Data
{
int p;
int d;
bool operator <(const Data &a)const
{
return d<a.d;
}
};
int n,m,s,t;
int len;
Data base[maxn<<6];
Data top()
{
return base[1];
}
void pop()
{
swap(base[1],base[len--]);
int pos=1;
int nxt;
while(true)
{
nxt=pos;
if(base[pos<<1]<base[nxt]&&(pos<<1)<=len)
nxt=pos<<1;
if(base[pos<<1|1]<base[nxt]&&(pos<<1|1)<=len)
nxt=pos<<1|1;
if(pos==nxt) break;
swap(base[pos],base[nxt]);
pos=nxt;
}
}
void push(Data val)
{
base[++len]=val;
int pos=len;
while((pos>>1)&&base[pos]<base[pos>>1])
{
swap(base[pos>>1],base[pos]);
pos>>=1;
}
return ;
}
Edge line[maxn<<1];
int head[maxn],tail=-1;
void add(int a,int b,int c,int d)
{
line[++tail].p=b;
line[tail].w=c;
line[tail].f=d;
line[tail].nxt=head[a];
head[a]=tail;
}
int h[maxn];
bool vis[maxn];
int dis[maxn];
int from[maxn];
int L[maxn];
int flow[maxn];
int Max_flow,Min_cost;
bool dijkstra(int begin,int end)
{
len=0;
for(int i=1;i<=n;i++)
{
dis[i]=0x7fffffff;
flow[i]=0x7fffffff;
from[i]=L[i]=vis[i]=0;
}
dis[begin]=0;
Data pas;
pas.p=begin;pas.d=0;
push(pas);
while(len)//手写堆怪我喽
{
pas=top();pop();
while(vis[pas.p]&&len>=1)
{
pas=top();
pop();
}
if(vis[pas.p]&&!len) break;
vis[pas.p]=true;
dis[pas.p]=pas.d;
for(int i=head[pas.p];i!=-1;i=line[i].nxt)
if(line[i].f>0&&!vis[line[i].p]&&dis[line[i].p]>dis[pas.p]+line[i].w+h[pas.p]-h[line[i].p])//判断,带上势
{
dis[line[i].p]=dis[pas.p]+line[i].w+h[pas.p]-h[line[i].p];//跟spfa一样的套路,就是多了个势
flow[line[i].p]=min(line[i].f,flow[pas.p]);
from[line[i].p]=pas.p;
L[line[i].p]=i;
Data nxt;
nxt.p=line[i].p;nxt.d=dis[line[i].p];
push(nxt);
}
}
return dis[end]!=0x7fffffff;
}
void MCMA(int begin,int end)
{
while(dijkstra(begin,end))//差不多跟spfa一样的格式,就是加了个h数组
{
int max_flow=flow[end];
Min_cost+=max_flow*(dis[end]-h[begin]+h[end]);
Max_flow+=max_flow;
for(int i=end;i!=begin;i=from[i])
{
line[L[i]].f-=max_flow;
line[L[i]^1].f+=max_flow;
}
for(int i=1;i<=n;i++)
h[i]+=dis[i];//累加,一定要累加,虽然不累加可能过几个点
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;i<=m;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
add(a,b,d,c);add(b,a,-d,0);//建边
}
MCMA(s,t);//跑费用流
printf("%d %d",Max_flow,Min_cost);//输出
return 0;
}

dijkstra 最小费用最大流的更多相关文章

  1. UVa 10806 Dijkstra,Dijkstra(最小费用最大流)

    裸的费用流.往返就相当于从起点走两条路到终点. 按题意建图,将距离设为费用,流量设为1.然后增加2个点,一个连向节点1,流量=2,费用=0;结点n连一条同样的弧,然后求解最小费用最大流.当且仅当最大流 ...

  2. [板子]最小费用最大流(Dijkstra增广)

    最小费用最大流板子,没有压行.利用重标号让边权非负,用Dijkstra进行增广,在理论和实际上都比SPFA增广快得多.教程略去.转载请随意. #include <cstdio> #incl ...

  3. P3381 【模板】最小费用最大流

    P3381 [模板]最小费用最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行 ...

  4. Luogu--3381 【模板】最小费用最大流

    题目链接 3381 [模板]最小费用最大流 手写堆版本 dijkstra   400+ms 看来优先队列的常数好大 #include<bits/stdc++.h> using namesp ...

  5. POJ 2135 Farm Tour (网络流,最小费用最大流)

    POJ 2135 Farm Tour (网络流,最小费用最大流) Description When FJ's friends visit him on the farm, he likes to sh ...

  6. 经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)

    哈夫曼编码与哈夫曼算法 哈弗曼编码的目的是,如何用更短的bit来编码数据. 通过变长编码压缩编码长度.我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit.但在很多情况下,数 ...

  7. [Ahoi2014]支线剧情[无源汇有下界最小费用可行流]

    3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1538  Solved: 940[Submit][Statu ...

  8. 2017"百度之星"程序设计大赛 - 初赛(B) 度度熊的交易计划 最小费用最大流求最大费用

    /** 题目:度度熊的交易计划 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6118 题意:度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题 ...

  9. 经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)

    题目来源 P3376 [模板]网络最大流 P2756 飞行员配对方案问题 P3381 [模板]最小费用最大流 最大流 最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建 ...

随机推荐

  1. js动画实现&&回调地狱&&promise

    1. js实现动画 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  2. Composite Design Pattern in Java--转

    https://dzone.com/articles/composite-design-pattern-in-java-1 The composite pattern is meant to &quo ...

  3. nyoj 456——邮票分你一半——————【背包思想搜索】

    邮票分你一半 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述      小珂最近收集了些邮票,他想把其中的一些给他的好朋友小明.每张邮票上都有分值,他们想把这些邮票分 ...

  4. Excle 导入DataSet

    using System.Data.OleDb;using System.Data; public void ReadExcelFiless()        {            //strin ...

  5. 全局数据 GetGlobalDataSet

    /// <summary> /// 获取全局数据 /// </summary> /// <returns></returns> public DataS ...

  6. 在 Azure Web 应用中创建 PHP 应用程序

    本分步指南将通过 Azure Web 应用帮助您启动并运行示例 PHP 应用程序.除 PHP 外,Azure Web 应用还支持其他语言,如 Java..NET.Node.JS.Python.Ruby ...

  7. JavaScirpt(JS)——js介绍及ECMAScript

    一.JavaScript历史发展 JavaScript语言的历史:http://javascript.ruanyifeng.com/introduction/history.html 1994年12月 ...

  8. 常见的media断点

    landscape mode是指宽度比高度宽的模式,也就是俗称的宽屏模式: portrait mode是指高度比宽度高的模式,也就是俗称的竖屏模式: /*#region SmartPhones */ ...

  9. File I/O 小结

    1 .I/0: input/output 2.java.io.File 3 .表示:文件或者文件夹(目录) 4. File f = new File("文件路径"); 5 .注意: ...

  10. 创建 XMLHttpRequest 对象时IE的兼容问题解决办法

    为了应对所有的现代浏览器,包括 IE5 和 IE6,请检查浏览器是否支持 XMLHttpRequest 对象.如果支持,则创建 XMLHttpRequest 对象.如果不支持,则创建 ActiveXO ...