【SPFA与Dijkstra的对比】CDOJ 1961 咸鱼睡觉觉【差分约束-负权最短路径SPFA】
差分约束系统,求最小值,跑最长路。
转自:https://www.cnblogs.com/ehanla/p/9134012.html
题解:设sum[x]为前x个咕咕中至少需要赶走的咕咕数,则sum[b]−sum[a−1]>=c表示[a,b]区间至少赶走c只。题目中选择的是最少,我们需要跑最长路,因存在负边,所以以SPFA进行操作。
d[v]>=d[u]+w,前面我们可以推出第一个式子sum[b]>=sum[a−1]+c,但是如果只连这些边,整张图连通不起来。我们发现i和i+1存在关系0<=sum[i+1]−sum[i]<=1,这个其实就是表示i+1那个位置赶与不赶。
推出第二个和第三个式子:sum[i]>=sum[i+1]−1,sum[i+1]>=sum[i]+0
由以上式子得到边:a−1点 b点 距离c
i+1点 i点 距离−1
i点 i+1点 距离0
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N=2e5+;
int n,k,cnt;
bool vis[N];
int head[N],d[N];
struct node
{
int to,next,w;
}edge[N]; void init()
{
cnt=;
memset(head,-, sizeof(head));
} void add(int u,int v,int w)
{
edge[cnt].to=v;edge[cnt].w=w,edge[cnt].next=head[u];head[u]=cnt++;
} void spfa()
{
memset(d,-INF,sizeof(d));
memset(vis,,sizeof(vis));
queue<int> q;
q.push();
d[]=;
vis[]=;
while(q.size())
{
int u=q.front();q.pop();
vis[u]=; // 可以重复入队,现在不在队内
for(int i=head[u];i!=-;i=edge[i].next)
{
int v=edge[i].to;
if(d[v]<d[u]+edge[i].w) // 最长路径
{
d[v]=d[u]+edge[i].w;
if(!vis[v])
{
q.push(v);
vis[v]=;
}
}
}
}
} int main()
{
init();
cin>>k>>n;
for(int i=;i<=n;i++)
{
int a,b,c;
cin>>a>>b>>c;
// d[b]-d[a-1] >= c
add(a-,b,c);
}
// 0 <= d[i+1]-d[i] <= 1
for(int i=;i<k;i++)
{
add(i,i+,);
add(i+,i,-); // 存在负数权值
}
spfa();
cout<<d[k]<<endl;
return ;
}
求单源最短路的算法SPFA:
算法中需要的变量
int N; //表示n个点,从1到n标号
int s,t; //s为源点,t为终点
int d[N]; //d[i]表示源点s到点i的最短路
int pre[N]; //记录路径(或者说记录前驱)
queue <int> q; //队列,
bool vis[N]; //vis[i]=1表示点i在队列中 vis[i]=0表示不在队列中
在整个算法中有顶点入队要记得标记vis数组,有顶点出队记得消除那个标记,顶点可以重复入队,这区别于dijkstra算法
队列+松弛操作:
读取队头顶点u,并将队头顶点u出队(消除标记);将与点u相连的所有点v进行松弛操作,如果能更新估计值(使d[v]变小),那么就更新,另外,如果点v没有在队列中,那么要将点v入队(记得标记),如果已经在队列中了,那么就不用入队
以此循环,直到队空为止就完成了单源最短路的求解
SPFA可以处理负权边
SPFA判断负环:如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)
int spfa_bfs(int s)
{
queue<int> q;
memset(d,0x3f, sizeof(d)); // 距离矩阵
memset(c,,sizeof(c)); // 入队次数
memset(vis,, sizeof(vis));
q.push(s);
vis[s]=;
c[s]++;
int OK=;
while(q.size())
{
int u=q.front();q.pop();
vis[u]=;
for(int i=head[u];i;i=next[i])
{
int v=ver[i];
if(d[v]>d[u]+w[i])
{
d[v]=d[u]+w[i];
if(!vis[v])
{
vis[v]=;
q.push(v);
c[v]++;
if(c[v]>N) // 超过入队次数上限,说明有负环
return OK=;
}
}
}
}
return OK;
}
Dijkstra的priority_queue写法与SPFA的queue写法对比:
- Dijkstra+heap是用小根堆,每次取出d中未访问的最小点,来更新距离,对于这个点来说,最小距离就是当前的d。
- SPFA是用双端队列,每次取出队头,来更新距离,它之后可能还会入队。是一种动态逼近法,因为每次松弛距离都会减小,所以松弛一定会有结束。如果一个点入队超过n次就存在负环。
Dijkstra
用STL中的优先队列实现堆:
while(优先队列非空)
-->队头出队,松弛它的边
-->松弛了的pair<新距离,点>入队
typedef pair<int,int> P;
priority_queue<P,vector<P>,greater<P> > q; // 最小堆
...
while(!q.empty()){ // O(V) 加上count<n可以优化一点点
int w=q.top().first, u=q.top().second;
q.pop(); // O(lgV)
if(vis[u])continue; vis[u]=true;
//++count;
for(int i=head[u];i;i=edge[i].next){ // Sum -> O(E)
int v=edge[i].to;
if(d[v]>d[u]+edge[i].w){
d[v]=d[u]+edge[i].w;
q.push(P(d[v],v)); // O(lgV)
}
}
}
SPFA:
while(队非空)
-->队头出队,取消标记,松弛它的边
-->松弛了且不在队内的点入队,并标记
while(!q.empty()){
int u=q.front(); q.pop();
vis[u]=false;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(d[v]>d[u]+edge[i].w){
d[v]=d[u]+edge[i].w;
if(!vis[v])vis[v]=true,q.push(v);
}
}
}
Dijkstra和Prim也很相似,它们的区别主要是d的含义,前者是到s的临时最短距离[s->每一点],后者是到树的临时最短距离[边长],相同点是,每次找最小的d更新其它点的距离。
【SPFA与Dijkstra的对比】CDOJ 1961 咸鱼睡觉觉【差分约束-负权最短路径SPFA】的更多相关文章
- POJ.1752.Advertisement(差分约束 最长路SPFA)
题目链接 \(Description\) 有\(n\)个人在一条直线上跑步,每个人的起点 \(Si\).终点 \(Ei\) 已知:每个点可以放一个广告牌,一个人\(i\)能看到的广告牌数量为 \(Ei ...
- HDU.1529.Cashier Employment(差分约束 最长路SPFA)
题目链接 \(Description\) 给定一天24h 每小时需要的员工数量Ri,有n个员工,已知每个员工开始工作的时间ti(ti∈[0,23]),每个员工会连续工作8h. 问能否满足一天的需求.若 ...
- POJ 3159 Candies 还是差分约束(栈的SPFA)
http://poj.org/problem?id=3159 题目大意: n个小朋友分糖果,你要满足他们的要求(a b x 意思为b不能超过a x个糖果)并且编号1和n的糖果差距要最大. 思路: 嗯, ...
- [ACM] 最短路算法整理(bellman_ford , SPFA , floyed , dijkstra 思想,步骤及模板)
以杭电2544题目为例 最短路 Problem Description 在每年的校赛里,全部进入决赛的同学都会获得一件非常美丽的t-shirt. 可是每当我们的工作人员把上百件的衣服从商店运回到赛场的 ...
- POJ 3159 Candies 解题报告(差分约束 Dijkstra+优先队列 SPFA+栈)
原题地址:http://poj.org/problem?id=3159 题意大概是班长发糖果,班里面有不良风气,A希望B的糖果不比自己多C个.班长要满足小朋友的需求,而且要让自己的糖果比snoopy的 ...
- 图论最短路径算法总结(Bellman-Ford + SPFA + DAGSP + Dijkstra + Floyd-Warshall)
这里感谢百度文库,百度百科,维基百科,还有算法导论的作者以及他的小伙伴们...... 最短路是现实生活中很常见的一个问题,之前练习了很多BFS的题目,BFS可以暴力解决很多最短路的问题,但是他有一定的 ...
- 图论算法》关于SPFA和Dijkstra算法的两三事
本来我是想把这两个算法分开写描述的,但是SPFA其实就是Dijkstra的稀疏图优化,所以其实代码差不多,所以就放在一起写了. 因为SPFA是Dijkstra的优化,所以我想来讲讲Dijkstra. ...
- luogu P3371 & P4779 单源最短路径spfa & 最大堆优化Dijkstra算法
P3371 [模板]单源最短路径(弱化版) 题目背景 本题测试数据为随机数据,在考试中可能会出现构造数据让SPFA不通过,如有需要请移步 P4779. 题目描述 如题,给出一个有向图,请输出从某一点出 ...
- 关于SPFA Bellman-Ford Dijkstra Floyd BFS最短路的共同点与区别
关于模板什么的还有算法的具体介绍 戳我 这里我们只做所有最短路的具体分析. 那么同是求解最短路,这些算法到底有什么区别和联系: 对于BFS来说,他没有松弛操作,他的理论思想是从每一点做树形便利,那么时 ...
随机推荐
- Linux内核的整体架构简介
1. 前言 本文是“Linux内核分析”系列文章的第一篇,会以内核的核心功能为出发点,描述Linux内核的整体架构,以及架构之下主要的软件子系统.之后,会介绍Linux内核源文件的目录结构,并和各个软 ...
- Linux 网络侦错:无法联机原因分析
所谓的软件问题,绝大部分就是 IP 参数设定错误啊,路由不对啊,还有 DNS 的 IP 设定错误等等的, 这些问题都是属于软件设定啦!只要将设定改一改,利用一些侦测软件查一查,就知道问题出在哪里了!基 ...
- C# 对话框使用整理
1.保存文件对话框 SaveFileDialog saveFile = new SaveFileDialog(); saveFile.Title = "save file"; sa ...
- centos7怎么永久修改hosname
centos7怎么永久修改hosname 其实,一般来说安装好虚拟机之后,一般都会进行修改hostname,之前也是在修改的时候,遇到过问题,但是没有深究,今天在修改的时候,好好研究了一下,之前看到好 ...
- springcloud-4:服务注册(hello-service)
服务端 请见 http://www.cnblogs.com/huiy/p/8668005.html 客户端: 主启动类 import org.springframework.boot.SpringAp ...
- mysql5.7 pxc
pxc优点总结:可以达到时时同步,无延迟现象发生完全兼容MySQL对于集群中新节点的加入,维护起来很简单数据的强一致性不足之处总结:只支持Innodb存储引擎存在多节点update更新问题,也就是写放 ...
- CentOS7.5从零安装Python3.6.6
ps:环境如标题 安装可能需要的依赖 yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlit ...
- vue 轮播图插件 vue-awesome-swiper
1.npm安装 npm install vue-awesome-swiper --save 2.vue 引入 //在main.js 中全局引入 import VueAwesomeSwiper from ...
- eclipse 安装教程
eclipse 安装教程 一:安装包下载: 链接: https://pan.baidu.com/s/1qZtt62o 密码: 4ak2 注:若 下载链接失效,请看本文公告的QQ群,请联系群主. 二:安 ...
- flask 初学1
py 文件中 from flask import Flask,redirect,request,url_for,jsonifyfrom Flask_5.config import Config fro ...