试题描述
输入数据给出一个有 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. perl6 登录phpmyadmin

    use HTTP::UserAgent; my $ua = HTTP::UserAgent.new; my $url = 'http://localhost/phpMyAdmin/index.php' ...

  2. [005] unique_sub_string

    [Description] Given a string, find the largest unique substring. e.g. str[] = "asdfghjkkjhgf&qu ...

  3. iTextSharp操作pdf之pdfCreater

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. ubuntu无法获得锁 /var/lib/dpkg -open 问题

    问题: 方法: sudo rm   /var/lib/dpkg/lock 然后再安装就可以了

  5. 一个好的Java时间工具类DateTime

    此类的灵感来源于C# 虽然网上有什么date4j,但是jar太纠结了,先给出源码,可以继承到自己的util包中,作为一个资深程序员,我相信都有不少好的util工具类,我也希望经过此次分享,能带动技术大 ...

  6. .Net Core 部署到 CentOS7 64 位系统中的步骤

    建议使用 root 管理员账户操作 1.安装工具 1.apache 2..Net Core(dotnet-sdk-2.0) 3.Supervisor(进程管理工具,目的是服务器一开机就启动服务器 上发 ...

  7. MySQL-事务特性

    1. 事务概念引入: 现实生活中,我们往往经常会进行转账操作,转账操作可以分为两部分来完成,转入和转出.只有这两部分都完成了才可以认为是转账成功.在数据库中,这个过程是使用两条语句来完成的,如果其中任 ...

  8. CentOS7中开机出现end_request:I/O error,dev fd0,sector 0的解决办法

    https://blog.csdn.net/wangjinyang_123/article/details/40583635

  9. IE7、IE8下使用escape、encodeURI传递中文参数乱码的问题及解决方案

    js跳转到指定页面,一旦escape()中文数据,浏览器就会终止和没有反应.上网搜了半天始终不得解.一种说法是,escape中文之后,url中出现了%u,IE7和IE8拒绝执行.目前看来差不多是这样的 ...

  10. import xxx from 和 import {xxx} from的区别

    1.vue import FunName from ‘../xxx’ 1.js export defualt function FunName() { return fetch({ url: '/ar ...