- POJ 3259 - Wormholes
- Time: 2000MS
- Memory: 65536K
- 难度: 初级
- 分类: 最短路径算法
0x00 POJ 原题
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.
Source
0x10 解题思路
利用虫洞的时光旅行,很有趣的一道题。涉及到图论的知识,关键是构造图,用 Bellman-Ford 算法找出负权环
Bellman-Ford 算法核心在于松弛,具体算法可以百度。
需要注意的就是输入说明 Input 这部分,很多人读不懂这段题意:
正权(双向)边部分:
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 toE that also moves the traveler back T seconds.
0x20 AC 源码
//Memory Time
//308K 204MS
#include<iostream>
using namespace std;
int dis[1001]; //源点到各点权值
const int max_w=10001; //无穷远
class weight
{
public:
int s;
int e;
int t;
}edge[5200];
int N,M,W_h; //N (1≤N≤500)fields 顶点数
//M (1≤M≤2500)paths 正权双向边
//W_h (1≤W≤200) wormholes 虫洞(回溯),负权单向边
int all_e; //边集(边总数)
bool bellman(void)
{
bool flag;
/*relax*/
for(int i=0;i<N-1;i++)
{
flag=false;
for(int j=0;j<all_e;j++)
if(dis[edge[j].e] > dis[edge[j].s] + edge[j].t)
{
dis[edge[j].e] = dis[edge[j].s] + edge[j].t;
flag=true; //relax对路径有更新
}
if(!flag)
break; //只要某一次relax没有更新,说明最短路径已经查找完毕,或者部分点不可达,可以跳出relax
}
/*Search Negative Circle*/
for(int k=0;k<all_e;k++)
if( dis[edge[k].e] > dis[edge[k].s] + edge[k].t)
return true;
return false;
}
int main(void)
{
int u,v,w;
int F;
cin>>F;
while(F--)
{
memset(dis,max_w,sizeof(dis)); //源点到各点的初始值为无穷,即默认不连通
cin>>N>>M>>W_h;
all_e=0; //初始化指针
/*read in Positive Paths*/
for(int i=1;i<=M;i++)
{
cin>>u>>v>>w;
edge[all_e].s=edge[all_e+1].e=u;
edge[all_e].e=edge[all_e+1].s=v;
edge[all_e++].t=w;
edge[all_e++].t=w; //由于paths的双向性,两个方向权值相等,注意指针的移动
}
/*read in Negative Wormholds*/
for(int j=1;j<=W_h;j++)
{
cin>>u>>v>>w;
edge[all_e].s=u;
edge[all_e].e=v;
edge[all_e++].t=-w; //注意权值为负
}
/*Bellman-Ford Algorithm*/
if(bellman())
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}