前言:众所周知: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. windows下libcurl+openssl编译与使用配置

    之前使用过libcurl, 编译也是最简单的版本, 不需要openssl, 即不需要支持https, 所以编译和使用都很正常. 但要使用openssl就很麻烦了, 我花了差不多两天去编译和调用, 记录 ...

  2. oracle dblink简介

    database link概述 database link是定义一个数据库到另一个数据库的路径的对象,database link允许你查询远程表及执行远程程序.在任何分布式环境里,database都是 ...

  3. spring-boot 1.4.x遇到的cpu高的问题

    如果你的spring-boot应用里tomcat线程耗cpu较高,并主要耗在做读取jar的操作上(堆栈类似下面),可能跟我们遇到同样的问题. CRC32.update(byte[], int, int ...

  4. 浅谈C#中HttpWebRequest与HttpWebResponse的使用方法

    1.第一招,根据URL地址获取网页信息get方法 public static string GetUrltoHtml(string Url,string type) { try { System.Ne ...

  5. Git连接远程服务器输入密码问题

    当遇到使用Git从远程pull 或者 push代码的时候提示输入密码的时候,毫无疑问SSH Key出问题了! 一.如果只是使用Git Bash,重新生成一下ssh,把新的id_rsa.pub添加到Gi ...

  6. 2017年10月29日 数据库查询总结&45道题

    日期函数: 当前时间:GetDate() 两个时间差:DateDiff() 一. 设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Tea ...

  7. SpringMVC:系统认识一下maven

    网上看了很多springMVC helloworld的教程,非常不满意:首先,maven构建的就很少,再者,绝大部分都是断章取义,让人不明就里.其中有几篇讲的好的,我摘录了一些,自己试着构建了一下项目 ...

  8. sublime开启vi编辑器功能,与vi常用快捷键

    sublime开启vi编辑器 install package -> vintageES 设置里面 ignored_packages 里面的vintage去掉 VI命令 游标控制 h 游标向左移 ...

  9. Cocos2d-js 开发记录:图片数据资源等的异步加载

    这里说的是在需要的使用加载图片,比如游戏中的某个关卡的图片,不用在游戏一开始就加载(万一用户玩不到那关,岂不是很冤,流量费了那么多),否则载入速度也慢.这种方式加载资源要用到cc.loader官方文档 ...

  10. Canvas知识点汇总

    本文主要记录Canvas基础知识汇总. 1.Canvas定义 <canvas> 元素是HTML5中的新元素,通过它可以在网页中绘制出所需的图形.<canvas>标签只是图形的容 ...