Spfa【p3385】【模板】负环(spfa)
顾z
你没有发现两个字里的blog都不一样嘛 qwq
题目描述
毒瘤数据要求判负环
分析:
还是融合了不少题解的思想的。
负环定义:
权值和为负的环
//在网络上并没有找到一个官方定义,暂且这么理解。
SPFA:
支持负边权的情况.
spfa是最短路算法.如果一个环上的边权有负的,我们可以重复走这条路来获得更小的边权,所以这可以作为我们使用spfa判断负环的根据
//如果一个位置入队次数不小于n次,那它一定位于环上,所以这可以作为我们的判断标准。
听说STL的队列比较慢,换掉!
但是如果手打队列的话
队尾指针队首指针一直++根本停不下来怎么办?
我们可以重复使用!
像这样↓
//这三行代码只是演示,并不是程序中这样写。
if(l>n)l=0;
if(r>n)r=0;
if(l<0)l=n;
//因为r一直增加或者重置为0,所以没必要判断r<0
考虑把dis值大的放在最下边,dis值小的放在最上边。
因为我们取出的位置一直是向前的,所以把dis值小的放在最下边
(也不能说是最下边,即放在刚刚取过的位置处,再比较一下与原位置dis值大小.)
至于为什么尽量去取dis值小的?
因为这些被更新过的点dis值小,我们可能是通过一条负边到达的此节点,我们再去对它更新一下,可以尽可能早的判断出负环.
//偷懒的话应该可以用优先队列来做,不过没有尝试,留给您了!
坑:
YE5是5!!! N0是0!!!
----------------AC代码-----------------
// 3106ms 改数据之前 (话说我也不知道啥时候改的.
//改数据之后 吸氧 571ms qwq.
// Creator: 顾z
// Date:2018.08.29
//------------------------------------------------
#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 100086
#define clear(a) memset(a,0,sizeof a)
#define rk for(RI i=1;i<=n;i++)
IL void read(int &x){
int f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,T,s;
struct code{int u,v,w;}edge[N<<1];
bool vis[N];
int head[N],tot,dis[N],cnt[N],q[N];
IL void add(int x,int y,int z){edge[++tot].u=head[x];edge[tot].v=y;edge[tot].w=z;head[x]=tot;}
IL bool spfa(int s)
{
int l,r;
l=r=0;
memset(dis,0x3f,sizeof dis);
clear(vis);clear(cnt);clear(q);
vis[s]=true;cnt[s]=1;dis[s]=0;
q[r++]=s;
while(l!=r)
{
int u=q[l++];
if(l>n)l=0;//重复使用
vis[u]=false;
for(RI i=head[u];i;i=edge[i].u)
{
if(dis[edge[i].v]>dis[u]+edge[i].w)
{
dis[edge[i].v]=dis[u]+edge[i].w;
cnt[edge[i].v]=cnt[u]+1;//题解思想.
if(cnt[edge[i].v]>=n and edge[i].w<0)
return true;
//这里需要判断一下边权是否为负。
//因为看到讨论区的一组hack数据,所以尝试改一下,
//然后就过啦~~~
if(!vis[edge[i].v])
{
vis[edge[i].v]=true;
if(dis[edge[i].v]>dis[q[l]])
{
l--;
if(l<0)
l=n;//重复使用
q[l]=edge[i].v;
}
else
{
q[r++]=edge[i].v;
if(r>n)
r=0;//重复使用
}
}
}
}
}
return false;
}
int main()
{
read(T);
while(T--)
{
s=1,tot=0;clear(head);
read(n),read(m);
for(RI i=1,u,v,w;i<=m;i++)
{
read(u),read(v),read(w);
add(u,v,w);
if(w>=0)add(v,u,w);
}
puts(spfa(s)?"YE5":"N0");
}
}
写在后面
//这份代码并没有考虑多个连通图中的负环情况
//因此依旧可以被hack掉.
//可能 正确性 or 内容是错误的
//提供参考啦~~
UPD
--2018.09.24.
为啥这个题的数据点改了 emmm
撤了10个毒瘤数据点?
本人尝试了神深搜spfa,依旧被卡.
码了一通宽搜spfa.
4355ms 卡过?
没了毒瘤数据点,感觉这题还是比较好做 emmm.
所以说为啥要改数据 QAQ
这里放一下代码.
注意边权有0的情况,也要建双向边.
//否则只有90pts qwq.
----------------(bfs)spfa----------------
//没有吸氧 4355ms. qwq
//吸氧 1138ms. qwq
#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 100086
#define clear(a) memset(a,0,sizeof a)
#define rk for(RI i=1;i<=n;i++)
using namespace std;
IL void read(int &x)
{
int f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,m,T;
struct code{int u,v,w;}edge[N];
bool vis[N];
int head[N],tot,dis[N],cnt[N];
IL void add(int x,int y,int z){edge[++tot].u=head[x];edge[tot].v=y;edge[tot].w=z;head[x]=tot;}
IL bool spfa(int now)
{
rk vis[i]=false,dis[i]=2147483647,cnt[i]=false;
queue<int>q;
q.push(now);
vis[now]=true;
dis[now]=0;
while(!q.empty())
{
int u=q.front();q.pop();vis[u]=false;
if(cnt[u]>=n)return true;
for(RI i=head[u];i;i=edge[i].u)
{
if(dis[edge[i].v]>dis[u]+edge[i].w)
{
dis[edge[i].v]=dis[u]+edge[i].w;
if(!vis[edge[i].v])
{
q.push(edge[i].v);
vis[edge[i].v]=true;
cnt[edge[i].v]++;
if(cnt[edge[i].v]>=n)return true;
}
}
}
}
return false;
}
int main()
{
read(T);
while(T--)
{
read(n),read(m);
tot=0;clear(head);
for(RI i=1,u,v,w;i<=m;i++)
{
read(u),read(v),read(w);
if(w<0)add(u,v,w);
else add(u,v,w),add(v,u,w);
}
puts(spfa(1)?"YE5":"N0");
}
}
Spfa【p3385】【模板】负环(spfa)的更多相关文章
- 洛谷P3385 [模板]负环 [SPFA]
题目传送门 题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个 ...
- 洛谷P3385判负环——spfa
题目:https://www.luogu.org/problemnew/show/P3385 两种方法,dfs和bfs: 一开始写的dfs,要把dis数组初值赋成0,这样从一个连着负边的点开始搜: 在 ...
- LG P2285 [模板]负环(spfa判负环)
题目描述 寻找一个从顶点1所能到达的负环,负环定义为:一个边权之和为负的环. 输入格式 第一行一个正整数T表示数据组数,对于每组数据: 第一行两个正整数N M,表示图有N个顶点,M条边 接下来M行,每 ...
- 负环--spfa
洛谷板子题 负环?是有负权边的环还是一个边权之和为负的环? 还没有准确的定义(那就先忽略吧qwq 判断负环的方法: 暴力枚举/spfa/mellman—ford/奇怪的贪心/超神的搜索 可惜我只会sp ...
- [P3385]【模板】负环 (spfa / bellman-ford)
终于开始认真对待图论了 因为听说一直是提高组的,动得很少,直到现在机房打提高的氛围下,开始学一些皮毛的东西 模板题目链接 这是一道求负环的题目,照理来说大家都是用spfa来判断负环的 但是我觉得bel ...
- 【洛谷 P3385】模板-负环(图论--spfa)
题目:有一个图有N个顶点,M条边.边用三个整数a b w表示,意思为a->b有一条权值为w的边(若w<0则为单向,否则双向).共T组数据.对于每组数据,存在负环则输出一行"YE5 ...
- 洛谷 P3385 【模板】负环 (SPFA)
题意:有一个\(n\)个点的有向图,从\(1\)出发,问是否有负环. 题解:我们可以用SPFA来进行判断,在更新边的时候,同时更新路径的边数,因为假如有负环的话,SPFA这个过程一定会无限重复的遍历这 ...
- Poj(3259),SPFA,判负环
题目链接:http://poj.org/problem?id=3259 Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submis ...
- 【洛谷P3385】模板-负环
这道题普通的bfs spfa或者ballen ford会T 所以我们使用dfs spfa 原因在于,bfs sfpa中每个节点的入队次数不定,退出操作不及时,而dfs则不会 既然,我们需要找负环,那么 ...
随机推荐
- 嵌入式(Embedded System)笔记 —— Cortex-M3 Introduction and Basics(下)
随着课内的学习,我想把每节课所学记录下来,以作查阅.以饲读者.由于我所上的是英文班课程,因此我将把关键术语的英文给出,甚至有些内容直接使用英文. 本次所介绍内容仍是关于Cortex-M3的基础内容,相 ...
- 图的最短路径:Dijkstra 和 Floyd
//最短路径 /* dijkstra Dijkstra(迪杰斯特拉)算法的核心思想是贪心策略+动态规划 http://www.programgo.com/article/4721147659/ Dij ...
- C:\Windows\System32目录可执行文件列表(Win7 64)
C:\Windows\System32>where /? C:\Windows\System32>where "c:\windows\system32:*.exe" & ...
- SSH集成cxf 发布restful webservice
首先讲一下什么是restful webservice ,这个问题网上一搜有很多博文去长篇大论的介绍它,但是最后你看完了也会觉得云里雾里的,所以我在这里简单的讲一下我理解的rest webservice ...
- PHP页面跳转总结
一.使用php内置函数:header()函数 <?php$url='./test.php'; header("Location:$url"); ?> 注意Locatio ...
- [转] Linux命令行编辑常用键
ctrl + a 将光标移动到命令行开头相当于VIM里shift+^ ctrl + e 将光标移动到命令行结尾处相当于VIM里shift+$ ctrl + 方向键左键 光标移动到前一个单词开头 ctr ...
- __PRETTY_FUNCTION__,__func__,__FUNCTION__
今天在看苹果的官方demo的时候,发现这个打印调用方法的参数,很是好奇,遂bing了一番. NSLog(@"----------------%s",__PRETTY_FUNCTIO ...
- 【bzoj2618】[Cqoi2006]凸多边形 半平面交
题目描述 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. 输入 第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形.第 ...
- Android性能优化之避免内存泄漏的建议
在android程序开发中,内存泄漏问题是比较常见的问题,相信有过一些android编程经历的程序猿都遇到过各种各样的内存泄漏.内存泄漏是造成应用程序OOM的主要原因之一,是编程中必须避免的问题.下面 ...
- Where to Run LightOJ - 1287(概率dp)
Where to Run LightOJ - 1287(概率dp) 题面长长的,看了半天也没看懂题意 不清楚的地方,如何判断一个点是否是EJ 按照我的理解 在一个EJ点处,要么原地停留五分钟接着走,要 ...