题目:

一开始被题目的梦幻给弄的晕乎乎。的却,作者很会yy。

意思是:

一个农夫有cas个田地,然后每个田地里面有nodeNum个结点,结点之间可能有多条路径(这是一个无向图),田地里还有w个虫洞(虫洞是某种可以搞穿越的东西,即时光倒流),那么从这个虫洞开始,又有s(起点),e(终点),t(花费的时间)。正常路径的(时间——t当然是正数的。但是虫洞的t(时间)却是负数的。因为时光倒流嘛。

最后题目要求你算算一个人是否可以时光倒流回到过去看到过去的自己。其实这个模型就是无向图求负环。比如你从a到b所需的时间为10,但是通过虫洞从b到a所花的时间是-15,就是说通过虫洞,你可以回到15秒之前的a,哈哈,10秒前你就在a,那么你当然可以看到自己咯(题外yy:至于看到自己后,能不能跟自己聊天,讲话,还只是看到一个幻想,还真不晓得。不过根据宇宙平行理论,嗯……)

解题方法:

解题的方法就是构建一个无向图,然后用spfa算法扫描看看是否含有负环就解决啦。至于这个负环的判断嘛,如果你的spfa是用队列来做的。那么只要标志每个节点入队的次数即可,当存在节点入队的次数超过了总节点的个数时,那么证明这个图存在负环。

还想不通可以参考这个:

spfa是使用队列进行渐近求最短路的方法:

思想为:

  1、只保存被更新但未扩展的节点(即未进队的节点)

做法:

    1、n建立一个队列,初始时队列里只有起始点,在建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空

2、n期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。
看看代码更健康:
/* 
   这道题花了一个小时在调整RuntimeError, 
   就因为主函数中的初始化,把点弄成了边去初始化map[][]. 
   这是白痴级别的错误 
*/ 
 
#include<iostream> 
#include<queue> 
using namespace std; 
 
int const maxNum=1001; 
int const Infinity=99999999; 
 
int map[maxNum][maxNum],dis[maxNum];//dis用来存放点的最佳路径 
int nodeNum,time[maxNum];//time用来记录结点入队的次数 
int vst[maxNum],visited[maxNum];//标志是否入队,标志点是否扫描过 
 
bool SPFA(int start)//经典的SPFA算法 

    int i,p; 
    queue<int> que; 
    memset(vst,0,sizeof(vst)); 
    memset(time,0,sizeof(time)); 
 
    for(i=1;i<=nodeNum;i++) 
        dis[i]=Infinity; 
     
    dis[start]=0; 
    vst[start]=1; 
    que.push(start); 
    time[start]++;//起点先标志入队一次 
    while(!que.empty()) 
    { 
        p=que.front(); 
        que.pop(); 
        vst[p]=0;         
        for(i=1;i<=nodeNum;i++) 
        { 
            visited[i]=true;//这里用来标志已经被扫描过的点。注意visited跟vst数组的区别 
            if(dis[p]+map[p][i]<dis[i]) 
            { 
                dis[i]=dis[p]+map[p][i]; 
                if(!vst[i]) 
                { 
                    que.push(i); 
                    time[i]++; 
                    if(time[i]>=nodeNum)//当同一结点入队次数超过点的总数-1,即大于等于nodeNum时,存在负环,此题的关键 
                        return true; 
                    vst[i]=1; 
                } 
            } 
        } 
    } 
    return false; 

 
int main(void) 

    int cas,n,num,i,s,e,w,j; 
    scanf("%d",&cas);//田地的个数 
    while(cas--) 
    { 
        scanf("%d%d%d",&nodeNum,&n,&num);//结点数,边数,虫洞数 
        for(i=1;i<=nodeNum;i++) 
            for(j=1;j<=nodeNum;j++) 
                map[i][j]=Infinity; 
        for(i=1;i<=n;i++) 
        { 
            scanf("%d%d%d",&s,&e,&w);//边的起点,边的终点,走这条边所花的时间 
            if(map[s][e]>=w) 
            { 
                map[s][e]=w;//注意重边这种情况,取最小的那个 
            } 
            if(map[e][s]>=w)//双向边,应该每次都比较一下,(但是这道题目不比较也过) 
            { 
                map[e][s]=w; 
            } 
        } 
        for(i=1;i<=num;i++) 
        { 
            scanf("%d%d%d",&s,&e,&w); 
            if(map[s][e]>-w) 
                map[s][e]=-w;//这道题目这里似乎说明得不是很严谨,如果一条边原来是Infinity,而现在有一个负的边,那不就替代了么 
                             //题目似乎被理想化了,这种情况不考虑在其中,不知道说得对不对,望高手指教 
        } 
        memset(visited,0,sizeof(visited)); 
        for(i=1;i<=nodeNum;i++)//考虑到图可能不是完全连通图,即存在离散的子图 
        { 
            if(visited[i])    continue;//增加这一步以减少不必要的计算 
            if(SPFA(i)) 
            { 
                 cout<<"YES"<<endl; 
                break; 
            } 
        }                                                                                                                                                                                             if(i==nodeNum+1) 
            cout<<"NO"<<endl; 
    } 
    return 0; 

转载于:https://www.cnblogs.com/cchun/archive/2011/08/14/2520126.html

PKU3259-Wormholes(SPFA判断负环,含题意)相关推荐

  1. POJ 3259 Wormholes【最短路/SPFA判断负环模板】

    农夫约翰在探索他的许多农场,发现了一些惊人的虫洞.虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径 ...

  2. UVA 558 SPFA 判断负环

    这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负 ...

  3. spfa 判断负环 (转载)

    当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍 时有负环,或者单个点的入队次数大于sqrt(点数)有负环.这样时间复杂度就降了很多了. ...

  4. Wormholes——Bellman-Ford判断负环

    [题目描述] While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A w ...

  5. 负环——spfa判断负环的两种方式

    第一种:(不推荐) 统计每个点的入队次数,如果某一个点入队了n次,则说明存在负环. 第二种: 统计当前每个点的最短路的边数,如果存在负环,负环上的某一个点的最短路边数一定会是正无穷,只要边数超过n(节 ...

  6. 算法基础课-搜索与图论-spfa-AcWing 852. spfa判断负环:spfa求负环板子

    文章目录 题目分析 题目链接 题目分析 来源:acwing 分析: dist[x] 表示从源点到x点的最短距离. spfa算法求最短路的算法步骤: 初始化一个队列,将起点入队. 取出队头元素t,遍历它 ...

  7. POJ 3259 Wormholes SPFA判负环

    思路:SPFA判负环 数组不要开太小-- (后面附一组测试数组) // by SiriusRen #include <queue> #include <cstdio> #inc ...

  8. poj3259 Wormholes(spfa判负环)

    题意:给m条路(S,E,T)代表点S.E之间双向边权重为T,紧接着给W个虫洞(S,E,T)代表S到E的有向边可以回到T秒前即权重为-T,问能不能通过虫洞看到看到初始的自己,即能不能回到初始点所在的时间 ...

  9. spfa判断负环( 负环判定 + spfa )

    给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数. 请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible. 数据保证 ...

最新文章

  1. 《工业控制网络安全技术与实践》一2.1.3 SCADA 系统未来的技术发展
  2. 使用DOSBox编译汇编代码
  3. Java中synchronized同步块的执行流程
  4. 【数据结构与算法】循环队列的Java实现
  5. 梦幻西游物价稳定的服务器,梦幻西游:三界功绩对服务器点卡比例的影响,鬼区比例比火区高...
  6. FullCalendar 五:FullCalendar应用——编辑与删除日程事件
  7. Cycle-1(循环)
  8. 疫情按下快进键,电商抢占市场红利需可靠的助力
  9. Go程序的一生是怎样的?
  10. java中equals,hashcode和==的区别
  11. 域名解析到指定端口_南京课工场IT培训:搭建nginx虚拟主机——基于域名、端口和IP...
  12. python怎样安装wordcloud(词云)文件
  13. python 文件上传 web_Python WebDriver 文件上传(一)
  14. JDY-19蓝牙模块介绍及主、从机调试演示
  15. emoji 表情包全套手机端pc都支持
  16. php运维知识,分享一些linux运维的基础知识
  17. 【综合复习_网络部分】
  18. 写给父亲的语音计算器(语音的加载播放C#,四)
  19. 从一名白纸交易者到稳定盈利交易员需要多长时间?
  20. Netflix创始人:我不要求996,照样市值万亿!

热门文章

  1. [深度学习] loss不下降的解决方法
  2. 机器学习【四】决策树
  3. 深入研究java.lang.Runtime类,Process类
  4. spring 操作对象写入mongo去除_class列
  5. oracle 如何更改为归档模式
  6. SAP手记之六:GUI安装后初始配置(中文语言包安装)
  7. CCNP的实验设备注意事项
  8. 开源大数据:Apache Pulsar
  9. 【机器学习】隐马尔可夫模型及其三个基本问题(三)模型参数学习算法及python实现
  10. Focal loss原理解析