前言:众所周知: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. 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤

    福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑         Java全栈大联盟   ...

  2. nginx打开php错误提示

    首先要编辑php配置文件: vi /etc/php.ini error_reporting = E_ERROR display_errors = On  因为我开启了php-fpm.所以,还要编辑 p ...

  3. ContextCapture水面约束(水面破洞修复)

      [问题描述] 对于水面而言,由于特征点较少,软件在计算时很难匹配正确,导致输出模型的水面通常是支离破碎的.软件针对这种情况提供了一个约束工具,用户手动的为水面添加平面约束后,输出的水面模型就会非常 ...

  4. CityBuilder导入OSGB,生成3DML填坑

    工具:CityBuilder 问题1:导入osgb时,中文路径报错 当导入osgb layer时,Input folder和output foder 中最好不要出现中文 否则可能报出如下错误: 日志: ...

  5. 转帖:kindeditor编辑区空格被隐藏,导致所见所得不一致的解决办法

    1.修改kindereditor-all.js中的 var re = /(\s)<(/)?([\w-:]+)((?:\s+|(?:\s+[\w-:]+)|(?:\s+[\w-:]+=[^\s&q ...

  6. (二) 修改IDEA自带的 maven 仓库

    详细可见教程 :https://www.yiibai.com/testng/ 1.新建一个maven项目 Maven简介: Maven是一个项目管理和综合工具.Maven提供了开发人员构建一个完整的生 ...

  7. Java工程路径及相对路径(转载)

    3. 新建文件,默认位于工程目录new File("xxx.txt").getAbsolutePath();例如输出,D:\workspaces\workspace1\myProj ...

  8. asp and javascript: sql server export data to csv and to xls

    <%@LANGUAGE="JAVASCRIPT" CODEPAGE="65001"%> <% //塗聚文 //20131021 functio ...

  9. jQuery可调整表和列宽插件-colResizable

    最基本的例子 引入JS <script src="js/jquery-1.8.0.min.js" type="text/javascript">&l ...

  10. javascript实现数据结构:线索二叉树

    遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作.如何找到遍历过程中动态得到的每个结点的直接前驱和直接后继(第一个和最后一个除外)?如何保存这些信息? 设一棵二叉树 ...