[POJ 3259] Wormholes [SPFA]

Wormholes

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 54432 Accepted: 20270

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.

题意:

FJ有N块农场,农场间有M条路, W个虫洞。通过每条路需要耗费一定时间t,而通过每个虫洞则会增加一定时间 t’。问FJ能否从某个农场出发,最后回到这个点的时间在出发之前(即时间为负)。

题解:

理解清楚题意之后,我们将其当作图来考虑,每个农场为一个点,M条路是权值为正的双向边,W个虫洞是权值为负的单向边。于是我们只需要判断图中是否存在负圈即可。因为如果存在负圈,FJ只需要选择负圈种的某一点作为起点,即可回到过去的这个点。而如果不存在负圈,意味着FJ选择任何一个点作为起点都不可能从过去到达这个点。

比较裸的模板题,直接用spfa判断图中是否存在负圈即可。注意建图时,路是双向的,虫洞是单向的。

//#define LOCAL
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <iostream>
#include <cstdlib>
#include <algorithm>

using namespace std;

#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn MAX_N
#define MOD mod
#define MMT(x,i) memset(x,i,sizeof(x))
#define REP(i, n) for(int i = 0; i < n; i++)
#define FOR(i, n) for(int i = 1; i <= n; i++)
#define pb push_back
#define mp make_pair
#define X first
#define Y second

const LL MOD = 1e9 + 7;
const double pi = acos(-1.0);
const double E = exp(1);
const double EPS = 1e-8;

const int MAX_N = 1000010;
const int MAX_V = 510;
int N, M, W;
int dis[MAX_V];
int cnt[MAX_V];
bool vis[MAX_V];
struct edge{
  int to, cost;
  edge(int a, int b): to(a), cost(b){}
};
vector<edge> G[MAX_V];
void addedge(int u, int v, int w)
{
  G[u].push_back(edge(v, w));
//  G[v].push_back(edge(u, w));
}
bool spfa_bfs(int s)
{
  MMT(dis, 0x3f);
  MMT(cnt, 0);
  MMT(vis, 0);
  queue<int> q;
  dis[s] = 0, cnt[s] = 1, vis[s] = 1;
  q.push(s);
  while(!q.empty())
  {
    int x = q.front();
    q.pop();
    vis[x] = 0;
    for(int i = 0; i< G[x].size(); i++)
    {
      int v = G[x][i].to, cost = G[x][i].cost;
      if(dis[v] > dis[x] + cost)
      {
        dis[v] = dis[x] + cost;
      //  cout << v << " " << dis[v] << endl;
        //if(dis[v] < 0)  return 0;
        if(!vis[v]){
          vis[v] = 1;
          cnt[v]++;
          q.push(v);
          if(cnt[v] > N)  return 0;
        }
      }
    }
  }
  return 1;
}
void init()
{
  for(int i = 0; i < MAX_V; i++)
    G[i].clear();
}
int main()
{
  #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
  #endif
  ios::sync_with_stdio(false);
  int T;
  int  u, v, w;
  cin >> T;
  while(T--)
  {
    cin >> N >> M >> W;
    init();
    REP(i, M)
    {
      cin >> u >> v >> w;
      addedge(u, v, w);
      addedge(v, u, w);
    }
    REP(i, W)
    {
      cin >> u >> v >> w;
      addedge(u, v, -w);
    }
    bool flag = 1;
      if(!spfa_bfs(1)){
        cout << "YES" << endl;
        flag = 0;
      }
    if(flag)  cout << "NO" << endl;
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值