POJ训练计划3259_Wormholes(Bellman-Ford)(SPFA)

 Wormholes
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ’s farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..NM (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

Input

Line 1: A single integer, 
F
F farm descriptions follow. 

Line 1 of each farm: Three space-separated integers respectively: 
N
M, and 
W 

Lines 2..
M+1 of each farm: Three space-separated numbers (
S
E
T) that describe, respectively: a bidirectional path between 
S and 
E that requires 
Tseconds to traverse. Two fields might be connected by more than one path. 

Lines 
M+2..
M+
W+1 of each farm: Three space-separated numbers (
S
E
T) that describe, respectively: A one way path from 
S to 
E that also moves the traveler back 
T seconds.

Output

Lines 1..
F: For each farm, output “YES” if FJ can achieve his goal, otherwise output “NO” (do not include the quotes).

Sample Input

2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8

Sample Output

NO
YES

Hint

For farm 1, FJ cannot travel back in time. 

For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.

解题报告 表示很不懂题目意思。。。 贴网上的题解翻译

意思是:

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

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

判断是否存在负环 Bellman-Ford 在经过n-1次松弛操作后,判断是否能继续松弛,如果还能松弛,则存在负环。。。

#include <iostream>
#include <stdio.h>
#include <string.h>
#define inf 99999999
#define min(x,y) ((x)>(y)?(y):(x))

using namespace std;
struct edges
{
    int v,u;
    int w;
} edge[30000];
int dis[30000];
int n,m,w;
int k;
int Bf()
{
    int i,j,f=0;
    for(i=0; i<=n; i++)
        dis[i]=inf;
    dis[1]=0;
    for(i=1; i<n; i++)//n-1次
        for(j=0; j<k; j++)
            if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
                dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
    for(j=0; j<k; j++)
        if(dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
            return 1;
    return 0;
}
int main()
{
    int tt;
    int i,j;
    scanf("%d",&tt);
    int s,e,t;
    while(tt--)
    {
        memset(edge,0,sizeof(edge));
        scanf("%d%d%d",&n,&m,&w);
        while(m--)
        {
            scanf("%d%d%d",&s,&e,&t);
            edge[k].u=s;
            edge[k].v=e;
            edge[k++].w=t;
            edge[k].v=s;
            edge[k].u=e;
            edge[k++].w=t;
        }
        while(w--)
        {
            scanf("%d%d%d",&s,&e,&t);
            edge[k].u=s;
            edge[k].v=e;
            edge[k++].w=-t;
        }
        if(Bf())printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

SPFA(bfs版)+(邻接表)
SPFAbfs形式,判断条件是存在一点入队次数大于总顶点数。

手残好几次。。。 边的数组大小开到了3万+才过,2万TLE,1万RE。。。 就算是无向边也没那么大。。。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#define inf 99999999
using namespace std;
struct node
{
    int v,w,next;
} edge[30010];
int n,m,w,cnt,head[510],v[510];
void add(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void spfa()
{
    int dis[510],i,j,countt[510];
    memset(countt,0,sizeof(countt));
    for(i=1; i<=n; i++)
        dis[i]=inf;
    queue<int>Q;
    Q.push(1);
    v[1]=1;
    dis[1]=0;
    while(!Q.empty())
    {
        int q=Q.front();
        Q.pop();
        v[q]=0;
        for(i=head[q]; i!=-1; i=edge[i].next)
        {
            int vv=edge[i].v;
            if(dis[vv]>dis[q]+edge[i].w)
            {
                dis[vv]=dis[q]+edge[i].w;
                if(!v[vv])
                {
                    countt[vv]++;
                    if(countt[vv]>=n)
                    {
                        printf("YES\n");
                        return;
                    }
                    Q.push(vv);
                    v[vv]=1;
                }
            }
        }
    }
    printf("NO\n");
    return ;
}
int main()
{
    int i,j,s,e,t,tt;
    scanf("%d",&tt);
    while(tt--)
    {
        memset(head,-1,sizeof(head));
        memset(edge,0,sizeof(edge));
        memset(v,0,sizeof(v));

        scanf("%d%d%d",&n,&m,&w);
        while(m--)
        {
            scanf("%d%d%d",&s,&e,&t);
            add(s,e,t);
            add(e,s,t);
        }
        while(w--)
        {
            scanf("%d%d%d",&s,&e,&t);
            add(s,e,-t);
        }
        spfa();
    }
    return 0;
}

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/juncoder/article/details/19978565
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞