试题描述
输入数据给出一个有 N 个节点,M 条边的带权有向图。要求你写一个程序,判断这个有向图中是否存在负权回路。如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于 0,就说这条路是一个负权回路。
如果存在负权回路,只输出一行 −1;如果不存在负权回路,再求出一个点S到每个点的最短路的长度。约定:S 到 S 的距离为
0,如果 S 与这个点不连通,则输出 NoPath。
输入
第一行三个正整数,分别为点数 N,边数 M,源点 S;
以下 M 行,每行三个整数 a,b,c,表示点 a,b之间连有一条边,权值为 c。
输出
如果存在负权环,只输出一行 −1,否则按以下格式输出:共 N 行,第 i 行描述 S 点到点 i 的最短路
如果 S 与 i 不连通,输出 NoPath;
如果 i=S,输出 0。
其他情况输出 S 到 i 的最短路的长度。
输入示例
6 8 1
1 3 4
1 2 6
3 4 -7
6 4 2
2 4 5
3 6 3
4 5 1
3 5 4
输出示例
0
6
4
-3
-2

先用DFS判断负环,然后跑最短路即可。

DFS具体判断负环的方法是:记录一个vis数组,表示在你这次搜索过程中有没有走到这个点,如果在搜索的时候,发现这个目标点vis==1了,并且你还可以更新这个目标点的dis,那么就存在负环。因为这就相当于你跑完一圈,dis又少了,那么这个环肯定是负的。

这里有一个优化:是大佬YSF、SYF和我们清华毕业的数学老师姚璐提出并证明的。一般判断负环时,我们会把dis初始值赋成INF,但是实际上,我们可以赋0。相当于DFS跑最短路的时候,遇到正边就不跑了,这样会节省很大的时间复杂度。那么怎么证明正确性呢?

首先,我们需要证明一点,对于一个负环,一定有一个点,从这个点到第起始点的所有边权都为负,因为如果有正的,dis为0的情况可能会被正的卡住。那么又怎么证明这个呢?

我们可以画一个函数图像,x坐标表示负环上的每个点,y表示到x点时经过的边权。画出来后,你会发现,一定有一个峰值,然后对于这个峰值建系,它右侧的值全都是负的了。

具体代码如下(注意我的dis赋成0也可以AC,也是一个上面说法的验证):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <queue>
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define in(a) a=read()
using namespace std;
inline int read(){
int x=,f=;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
f=-;
for(;isdigit(ch);ch=getchar())
x=x*+ch-'';
return x*f;
}
int T;
int flag=;
int n,m,s;
int total=,nxt[],head[],to[],val[];
int vis[],dis[],book[];
int q[];
inline void adl(int a,int b,int c){
total++;
to[total]=b;
val[total]=c;
nxt[total]=head[a];
head[a]=total;
return ;
}
queue <int> Q;
inline void dfs(int u){
book[u]=;
for(int e=head[u];e;e=nxt[e]){
if(dis[to[e]]>dis[u]+val[e]){
dis[to[e]]=dis[u]+val[e];
if(vis[to[e]]){
flag=;
return ;
}
if(flag)
return ;
vis[to[e]]=;
dfs(to[e]);
vis[to[e]]=;
}
}
return ;
}
void SPFA(int st){
memset(vis,,sizeof(vis));
memset(dis,,sizeof(dis));
int hea=,tail=;
//q[hea]=st;
Q.push(st);
dis[st]=;
while(!Q.empty()/*tail>=hea*/){
int u=Q.front();
//hea++;
Q.pop();
vis[u]=;
for(int e=head[u];e;e=nxt[e])
if(dis[to[e]]>dis[u]+val[e]){
dis[to[e]]=dis[u]+val[e];
if(!vis[to[e]]){
vis[to[e]]=;
Q.push(to[e]);
}
}
}
return ;
}
int main()
{
total=flag=;
//memset(dis,127,sizeof(dis));
in(n);in(m);in(s);
int a,b,c;
REP(i,,m){
in(a);in(b);in(c);
adl(a,b,c);
}
REP(i,,n)
if(!book[i]){
memset(vis,,sizeof(vis));
dfs(i);
if(flag) break;
}
if(flag){
cout<<-<<endl;
return ;
}
SPFA(s);
REP(i,,n)
if(dis[i]>)
cout<<"NoPath"<<endl;
else cout<<dis[i]<<endl;
}

Loj10086 Easy SSSP的更多相关文章

  1. vijosP1053 Easy sssp

    vijosP1053 Easy sssp 链接:https://vijos.org/p/1053 [思路] SPFA. 题目中的陷阱比较多,但是只要中规中矩的写SPFA诸如:s与负圈不相连,有重边的情 ...

  2. Easy sssp

    Easy sssp 时间限制: 1 Sec  内存限制: 128 MB提交: 103  解决: 20[提交][状态][讨论版] 题目描述 输入数据给出一个有N(2  < =  N  < = ...

  3. Easy sssp(spfa)(负环)

    vijos    1053    Easy sssp 方法:用spfa判断是否存在负环 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,00 ...

  4. SPFA_YZOI 1662: Easy sssp

    题目描述 输入数据给出一个有N(2  < =  N  < =  1,000)个节点,M(M  < =  100,000)条边的带权有向图.  要求你写一个程序,  判断这个有向图中是 ...

  5. Vijos1053 Easy sssp[spfa 负环]

    描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...

  6. vijos 1053 Easy sssp

    描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...

  7. Easy sssp(vijos 1053)

    描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...

  8. Vijos——T1053 Easy sssp

    https://vijos.org/p/1053 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程 ...

  9. Easy sssp(spfa判负环与求最短路)

    #include<bits/stdc++.h> using namespace std; int n,m,s; struct node{ int to,next,w; }e[]; bool ...

随机推荐

  1. linux学习记录.1.安装

    最近想了想决定开始学习linux. 在百度了一番后开始了安装,虚拟机VirtualBox,ubuntu. 基于VirtualBox虚拟机安装Ubuntu图文教程: http://blog.csdn.n ...

  2. PHP对象2: 构造函数与析构函数

    当一个对象的所有引用都没有时, 一个对象才消失, 这时才执行析构函数 <?php class firecat{ public $name; function say(){ echo 'I lov ...

  3. python OS 模块 文件目录操作

    Python OS 模块 文件目录操作 os模块中包含了一系列文件操作的函数,这里介绍的是一些在Linux平台上应用的文件操作函数.由于Linux是C写的,低层的libc库和系统调用的接口都是C AP ...

  4. C++之 extern C的作用详解

    extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码.加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C+ ...

  5. python requests模块手动设置cookies的几种方式

    def use_cookie(self): cookies="YF-V5-G0=731b77772529a1f49eac82a9d2c2957f; SUB=_2AkMsEgief8NxqwJ ...

  6. juery下拉刷新,div加载更多元素并添加点击事件(二)

    buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...

  7. [转载]ACE的陷阱

    转自: http://blog.csdn.net/fullsail/article/details/2915685 坦白说,使用这个标题无非是希望能够吸引你的眼球,这篇文章的目的仅仅是为了揭示一些AC ...

  8. go语言入门(三)

    条件语句 go语言的条件语句结构如下: go语言的条件语句和其他语言类似.简单列举下: 1.if 语句,布尔表达式不需要括号 if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } 2 ...

  9. ubuntu查看mysql版本的几种方法

    ubuntu查看mysql版本的几种方法 mysql 1:在终端下:mysql -V(大写) //代码 $ mysql -V mysql Ver 14.14 Distrib 5.5.46, for d ...

  10. python【项目】:选课系统【简易版】

    功能要求 角色:学校.学员.课程.讲师要求:1. 创建学校2. 创建课程3. 课程包含,周期,价格,通过学校创建课程4. 通过学校创建班级, 班级关联课程.讲师5. 创建学员时,选择学校,关联班级5. ...