POJ3259 Wormholes

题干

题意

在探索他的许多农场时,农夫约翰发现了许多神奇的虫洞。虫洞是非常奇特的,因为它是一条单行道,可以在你进入虫洞之前的时间把你送到目的地! FJ的每个农场都包括N(1≤N≤500)个编号为1…N的田地,M(1≤M≤2500)条路径,和W(1≤W≤200)个虫洞。
由于FJ是一个狂热的时间旅行爱好者,他想做以下事情:从某个领域开始,通过一些路径和虫洞旅行,并在他最初出发前的某个时间返回到起始领域。也许他将能见到自己 : )
为了帮助FJ发现这是否可行,他将向你提供到F(1≤F≤5)的农场的完整地图。任何路径都不会超过10,000秒,任何虫洞都不能使FJ在时间上退回超过10,000秒。

输入

第一行给出F,即F组测试数据。
每组测试数据的第一行给出三个整数,n,m,w。n个点,m条通路是正权的双向路径,w条虫洞是负权的单向通路。
此后的第2行到第1+m行,是三个整数s,e,t分别表示s节点到e节点(可反),消耗时间为t。
此后的第2+m行到第1+m+w行,是三个整数s,e,t分别表示s节点到e节点(不可反),减少时间为t。

输出

针对每组测试数据,能够在他最初出发前的某个时间返回到起始区域,输出YES,否则输出NO。

样例输入

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

样例输出

NO
YES

题解

思路

首先本题的思路和poj1086类似,所以按照那个思路应该也可行,都是在寻找环。
我之前学习了一下Bellman-Ford算法,正好在本题实验了一下,也顺利通过了。
不过需要注意的是,每一个普通路径都是双向通路,不要忘了每条路径需要判断两次。

提交代码

#include <stdio.h>

int vis[506],way[2505][3],wor[305][3];

int n,m,w;

bool bellman(){
  bool flag = false;
  for(int i = 0 ; i < n - 1 ; i++){
    flag = false;
    for(int j = 0 ; j < m ; j++){
      if( vis[way[j][1]] > vis[way[j][0]] + way[j][2] ){
        vis[way[j][1]] = vis[way[j][0]] + way[j][2];
        flag = true;
      }
      if( vis[way[j][0]] > vis[way[j][1]] + way[j][2] ){
        vis[way[j][0]] = vis[way[j][1]] + way[j][2];
        flag = true;
      }
    }

    for(int j = 0 ; j < w ; j++){
      if( vis[wor[j][1]] > vis[wor[j][0]] - wor[j][2] ){
        vis[wor[j][1]] = vis[wor[j][0]] - wor[j][2];
        flag = true;
      }
    }
    if (!flag)
      break;
  }

  flag = false;
  for(int j = 0 ; j < m ; j++){
    if( vis[way[j][1]] > vis[way[j][0]] + way[j][2] ){
      vis[way[j][1]] = vis[way[j][0]] + way[j][2];
      flag = true;
    }
  }

  for(int j = 0 ; j < w ; j++){
    if( vis[wor[j][1]] > vis[wor[j][0]] - wor[j][2] ){
      vis[wor[j][1]] = vis[wor[j][0]] - wor[j][2];
      flag = true;
    }
  }
  return flag;
}

int main(){
  int times;
  scanf("%d",&times);
  for(int t = 0 ; t < times ; t++){
    for(int i = 0 ; i < 503 ; i++)
      vis[i] = 7000000;
    vis[0] = 0;
    scanf("%d%d%d",&n,&m,&w);
    int tmp[3];
    for(int i = 0 ; i < m ; i++){
      scanf("%d%d%d",&tmp[0],&tmp[1],&tmp[2]);
      for(int j = 0 ; j < 3 ; j++){
        way[i][j] = tmp[j];
      }
    }
    for(int i = 0 ; i < w ; i++){
      scanf("%d%d%d",&tmp[0],&tmp[1],&tmp[2]);
      for(int j = 0 ; j < 3 ; j++){
        wor[i][j] = tmp[j];
      }
    }
    bool isVis = bellman();
    if(isVis){
      printf("YES\n");
    }else{
      printf("NO\n");
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值