题目链接:http://poj.org/problem?id=3259
题目大意:空间中有很多点,有一些点之间存在虫洞。给出一些从一个点到另一个点的路,这些路径会花费一个时间(这些路径是双向的),同时给出一些虫洞,通过虫洞从a点到达b点后会倒流一定的时间。问从第一个点出发通过一系列的虫洞和路径回到第一个点后能不能回到过去。
其实就是判断图中有没有负权回路,标准的Bellman_Ford算法,我就是为了学这个算法才找到这个题目的。要注意的是路径是双向的,而虫洞是单向的。
///2014.7.18
///poj3259
//Accepted 756K 94MS G++ 1655B 2014-07-19 14:46:42
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct Edge{
int u,v; //起点和终点
int l; //边长
};
int n,m; //n是点数,m是边数
const int N=550,M=5500; //问题中给出的可能的最大点数和最大边数(无向边算两条边)
const int MAXL = 0x3f3f3f3f; //边的无限长
Edge edge[M+10]; //边集
int pre[N+10]; //从源点到该点的路径上该点的前驱
int dist[N+10]; //从源点到该点的最短距离
bool relax( Edge e ){
if( dist[e.v] > dist[e.u]+e.l ){
dist[e.v] = dist[e.u]+e.l;
pre[e.v] = e.u;
return true;
}
return false;
}
bool bellman(int s){
for(int i=0 ; i<n ; i++){
dist[i] = MAXL;
pre[i] = -1;
}
dist[s] = 0;
bool change = false;
for(int i=1 ; i<n ; i++){
change = false;
for(int j=0 ; j<m ; j++){
if( relax(edge[j]) )
change = relax;
}
if( !change )
break;
}
for(int i=0 ; i<m ; i++){
if( relax(edge[i]) )
return false;
}
return true;
}
int nn,mm,ww;
void init(){
scanf("%d%d%d",&nn,&mm,&ww);
n = nn;
int a,b,c;
m = 0;
for(int i=0 ; i<mm ; i++){
scanf("%d%d%d",&a,&b,&c);
a--,b--;
edge[m].u = a, edge[m].v = b, edge[m].l = c;
m++;
edge[m].u = b, edge[m].v = a, edge[m].l = c;
m++;
}
for(int i=0 ; i<ww ; i++){
scanf("%d%d%d",&a,&b,&c);
a--,b--;
edge[m].u = a, edge[m].v = b, edge[m].l = 0-c;
m++;
}
}
int main(){
int t;
scanf("%d",&t);
while( t-- ){
init();
if( bellman(0) )
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
return 0;
}