Loj10086 Easy SSSP
|
试题描述
|
|
输入数据给出一个有 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的更多相关文章
- vijosP1053 Easy sssp
vijosP1053 Easy sssp 链接:https://vijos.org/p/1053 [思路] SPFA. 题目中的陷阱比较多,但是只要中规中矩的写SPFA诸如:s与负圈不相连,有重边的情 ...
- Easy sssp
Easy sssp 时间限制: 1 Sec 内存限制: 128 MB提交: 103 解决: 20[提交][状态][讨论版] 题目描述 输入数据给出一个有N(2 < = N < = ...
- Easy sssp(spfa)(负环)
vijos 1053 Easy sssp 方法:用spfa判断是否存在负环 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,00 ...
- SPFA_YZOI 1662: Easy sssp
题目描述 输入数据给出一个有N(2 < = N < = 1,000)个节点,M(M < = 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是 ...
- Vijos1053 Easy sssp[spfa 负环]
描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...
- vijos 1053 Easy sssp
描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...
- Easy sssp(vijos 1053)
描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一 ...
- Vijos——T1053 Easy sssp
https://vijos.org/p/1053 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图. 要求你写一个程 ...
- Easy sssp(spfa判负环与求最短路)
#include<bits/stdc++.h> using namespace std; int n,m,s; struct node{ int to,next,w; }e[]; bool ...
随机推荐
- hdu 5373 The shortest problem(杭电多校赛第七场)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5373 The shortest problem Time Limit: 3000/1500 MS (J ...
- js判断手机端(Android手机还是iPhone手机)
/** * [isMobile 判断平台] * @param test: 0:iPhone 1:Android */ function ismobile(test){ var u = navigato ...
- idea 控制台乱码
第一步:修改intellij idea配置文件: 找到intellij idea安装目录,bin文件夹下面idea64.exe.vmoptions和idea.exe.vmoptions这两个文件,分别 ...
- Linux 基础——常用的Linux网络命令
一.学Linux网络命令有什么好处 网络的出现,我们的生活更方便了,处理事情的效率也越来越高,也可以看到全世界文化的差异.同时我们接受新事物的信息越来越来强,新事物的信息也越来越来多.网络对于我们尔等 ...
- 洛谷P1420 最长连号 题解
题目传送门 这道题我是打暴力的...(尴尬) 所以直接是O(N2)的时间,但好像没有炸,数据很水... #include<bits/stdc++.h> using namespace st ...
- django的orm中F对象的使用
今天不巧就用上了. 就是将数据库的字段,自增1的场景. from django.db.models import F DeployPool.objects.filter(name=deployvers ...
- day3修改配置文件
有如下配置文件,在指定文件位置添加一条新的记录: global log 127.0.0.1 local2 daemon maxconn log 127.0.0.1 local2 info defaul ...
- 面试题13:在O(1)时间删除链表节点
注意分情况讨论: 1. 要删除的不是尾节点 2. 链表只有一个节点 3. 链表中有多个节点,删除尾节点 void DeleteNode(ListNode** pListHead, ListNode* ...
- 5 Linux网络编程基础API
5.1 socket地址API 大端字节序(网络序):高位在低址,低位在高址 小端字节序(主机序):低位在低址,高位在高址 判断,利用联合的特性: #include <iostream> ...
- ASP.NET中登录功能的简单逻辑设计
ASP.NET中登录功能的简单逻辑设计 概述 逻辑设计 ...