POJ3259 Wormholes

标签:spfa+邻接表判断负权
错误点:多组数据时没有对vector进行清空

Wormholes
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 71066 Accepted: 26409

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…N, M (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 T seconds 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.

译文摘自https://blog.csdn.net/zitian246/article/details/76082393

t译文:农夫约翰在探索他的许多农场,发现了一些惊人的虫洞。虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1…N,之间有M(1≤M≤2500)条路径,W(1≤W≤200)个虫洞。作为一个狂热的时间旅行FJ的爱好者,他要做到以下几点:开始在一个区域,通过一些路径和虫洞旅行,他要回到最开时出发的那个区域出发前的时间。也许他就能遇到自己了:)。为了帮助FJ找出这是否是可以或不可以,他会为你提供F个农场的完整的映射到(1≤F≤5)。所有的路径所花时间都不大于10000秒,所有的虫洞都不大于万秒的时间回溯。
输入 第1行:一个整数F表示接下来会有F个农场说明。 每个农场第一行:分别是三个空格隔开的整数:N,M和W
第2行到M+1行:三个空格分开的数字(S,E,T)描述,分别为:需要T秒走过S和E之间的双向路径。两个区域可能由一个以上的路径来连接。 第M
+2到M+ W+1行:三个空格分开的数字(S,E,T)描述虫洞,描述单向路径,S到E且回溯T秒。 输出 F行,每行代表一个农场 每个农场单独的一行,” YES”表示能满足要求,”NO”表示不能满足要求。 NO YES

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;

typedef long long ll;
const int maxn =  1005;
const int INF = 0x3f3f3f3f;     //无穷大
const int inf = 0x3f;

struct edge {
    int e,w;//终点,边的值
    edge(int _e,int _w) {       //构造函数,使用edge(a,b) 可以直接构造一个e = a,w = b结构体
        e = _e,w = _w;
    }
    //如果需要申请结构体变量,还需要加上下面这个构造函数
    //edge(){};(对没错里面都是空的)
};
vector<edge> Map[maxn];         //邻接表存图
bool vis[maxn];                 //该点是否在队列中
int dis[maxn];                  //初始点到每点的最短距离
int cnt[maxn];  //该点用了几次,判断是否有负权,负环
int n;
int spfa(int a) {
    memset(dis,inf,(n+1)<<2);   //将数组中前n+1个数初始化为无穷大
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    dis[a] = 0;
    vis[a] = true;
/*上面都是和Dijkstra一样的,接下来才是重头*/
/*Dijkstra:每次找权值最小的边,然后根据这个边所连的点更新dis数组
所以每n次操作只能找出一个点来
   SPFA:如果该边可以松弛且连接的点未被使用,就把该边连接的那个点存进队列等待更新
   所以每经过一个点就可以把该点所有边所连接的点(可以被松弛的)都记录然后更新
*/

        queue<int>q;
        q.push(a);
    //    printf("-------%d\n",a);
        cnt[a]++;
        while(!q.empty()) {
            int buf = q.front();                //取出队首的点
            q.pop();
            vis[buf] = 0;

            for(int i=0;i<Map[buf].size();i++)
            {
                int p = Map[buf][i].e;          //取出队首的点
                int w = Map[buf][i].w;
                if(dis[buf]+w < dis[p])
                {       //如果可以松弛就更新dis数组,此处和Dijkstra一样
                    dis[p] = dis[buf]+w;        //松弛的同时如果该点未被访问就把该点扔进队列
                    if(!vis[p]) {               //不同的地方,如果p点未被使用,则将其放入队列(也就是p点可以被松弛)
                        cnt[p]++;
    //                    printf("------%d\n",p);
                        if(cnt[p]>n)
                            return 1;
                        q.push(p);
                        vis[p] = 1;
                    }
                }
            }

        }
    //    for(int i=1;i<=n;i++)
    //        {
    //            printf("%d--%d\n",i,cnt[i]);
    //        }
        return 0;
    }
    int main()
    {
        int f,m,w,s,e,t,i,j;
        scanf("%d",&f);
        while(f--)
        {
        	memset(Map,0,sizeof(Map));
            scanf("%d%d%d",&n,&m,&w);
            //输入路径
            for(i=0;i<m;i++)
            {
                scanf("%d%d%d",&s,&e,&t);
                Map[s].push_back(edge(e,t));
                Map[e].push_back(edge(s,t));
            }
            //输入虫洞
            for(i=0;i<w;i++)
            {
                scanf("%d%d%d",&s,&e,&t);
                Map[s].push_back(edge(e,-t));
            }
//            for(i=0;i<n;i++)
//    		{
//    			//for(j=0;j<n;j++)
//    			{
//    				printf("%d  %d-----------",i,j);
//    				printf("%d  %d\n",Map[1][0].e,Map[1][0].w);
//    				//printf("aaaaa");
//    			}
//
//    		 }
            if(spfa(1))
                printf("YES\n");
            else
                printf("NO\n");
        }

        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值