poj-3259 Wormholes **

/*
* Bellman_Ford 判断负环
*
* 注意可能有平行边,只需保留最小的权值
*
* 【转】
* 此题虽然是最最基础的bellman_ford,但用来加深理解还是可以的:
* 1)bellman_ford 究竟要relax多少次,当从1到n存在且存在1 -> 2, 2 -> 3 ...n-1 -> n这样的边时,
* 从1开始relax,到n显然是需要n-1次的,而如果其中存在负环的话,若relax次数大于n-1,总是存在新的可以收缩的点,
* 因此最科学的次数是先做n-1次,再做第n次:
* 如果n-1次relax前已经不存在,则可以认为提前结束
* 若果第n次relax时仍有可relax点,则有负环的存在
* 2)对于此题,如何控制初值,一个比较原始的想法是,枚举起点,这样的时间复杂度大约为O(n^4),但是还是可以过...
* 而经过观察发现,假设有一个原点0,到所有点的距离都是0,那么我们只需要从这个原点出发去判断图中可能出现的负环,
* 因此我们只需要置初值dis[1..n]全部为0(任意相同值均可),做一次bellman_ford即可,而有不少的程序默认从1出发,一个简单的例子:
* (即只要有负环就行~)
*
* 开始用的邻接矩阵,TLE,。。
*
*
*/

#include
<cstdio>
#include
<cstring>
using namespace std;

const int inf = 100000000;
const int maxN = 500 + 5;
int f, n, m, w, totEdgeNum, G[maxN][maxN];
int d[maxN];

struct SEdge{
int s, e, w;
};
SEdge edge[maxN
* maxN];

bool bellmanFord(){
memset(d,
0, sizeof(d));

bool flag;
for(int i=1; i<n; i++){
flag
= 0;
for(int j=0; j<totEdgeNum; j++){
if(d[edge[j].e] > d[edge[j].s] + edge[j].w){
d[edge[j].e]
= d[edge[j].s] + edge[j].w;
flag
= 1;
}
}
if(!flag) break;
}

for(int j=0; j<totEdgeNum; j++){
if(d[edge[j].e] > d[edge[j].s] + edge[j].w)
return true;
}

return false;
}

int main(){
scanf(
"%d", &f);
while(f--){
scanf(
"%d%d%d", &n, &m, &w);

for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
G[i][j]
= inf;

int s, e, t;
for(int i=1; i<=m; i++){
scanf(
"%d%d%d", &s, &e, &t);
G[s][e]
= G[s][e] < t ? G[s][e] : t;
G[e][s]
= G[e][s] < t ? G[e][s] : t;
}
for(int i=1; i<=w; i++){
scanf(
"%d%d%d", &s, &e, &t);
G[s][e]
= G[s][e] < -t ? G[s][e] : -t;
}

totEdgeNum
= 0;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(G[i][j] != inf){
edge[totEdgeNum].s
= i;
edge[totEdgeNum].e
= j;
edge[totEdgeNum
++].w = G[i][j];
}
}
}

if(bellmanFord())
printf(
"YES\n");
else printf("NO\n");
}

return 0;
}

你可能感兴趣的:(orm)