Bellman-Ford算法之二

//poj 3259 Wormholes,源点不明确


//与spfa算法不同,当源点不明确时,bellman_ford算法不用添加超源点,
//因为它对图中每一条边都为做n-1次松弛,就保证每个顶点都得到更新。


//Bellman-Ford算法,求负权回路
//John的农场里field块地,path条路连接两块地,是双向边,hole个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。
//我们的任务是知道会不会在从某块地出发后又回来,看到了离开之前的自己,即是求是否存在负权回路
#include <iostream>
using namespace std;

const int maxint = 99999;
typedef
struct Edge
{
int u, v;
int weight;
}Edge;

Edge edge[
10000];
int dist[502],nodenum, edgenum;
int F,N,M,W;

void init()
{
nodenum
=N;
edgenum
=2*M+W;
memset(dist,
0,sizeof(dist)); //赋初值,没有明确的源点
int s,t,p,j=1;
for(int i=1; i<=M+W;++i)
{
cin
>>s>>t>>p;
if(i<=M)
{
edge[j].u
=s;edge[j].v=t;edge[j++].weight=p; //field之间是双向的
edge[j].u=t;edge[j].v=s;edge[j++].weight=p;
}
else
{
edge[j].u
=s;edge[j].v=t;edge[j++].weight=-p; //wormholes之间是单向的
}
}
}
bool relax(int u, int v, int weight)
{
if(dist[v] > dist[u] + weight)
{
dist[v]
= dist[u] + weight;
return 1;
}
return 0;
}
bool Bellman_Ford()
{
for(int i=1; i<=nodenum-1; ++i)
{
int tag=1;
for(int j=1; j<=edgenum; ++j)
if(relax(edge[j].u, edge[j].v, edge[j].weight))
tag
=0;
if(tag==1)
break;
}
for(int i=1; i<=edgenum; ++i)
if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)
return 0;
return 1;
}
int main()
{
cin
>>F;
while(F--)
{
cin
>>N>>M>>W;
init();
if(Bellman_Ford())
printf(
"NO\n");
else
printf(
"YES\n");
}
return 0;
}


//对于此题,如何控制初值,一个比较原始的想法是,枚举起点,这样的时间复杂度大约为O(n^4),但是还是可以过...
//而经过观察发现,假设有一个原点0,到所有点的距离都是0,那么我们只需要从这个原点出发去判断图中可能出现的负环,
//因此我们只需要置初值dis[1..n]全部为0(任意相同值均可),做一次bellman_ford即可,
//而有不少的程序默认从1出发,



//首先,一个不需要确定起始点判断负权回路的方法是把dis[1..n]全部置为0,
//然后做bellman_ford,该方法实际上是以负权路径的端点作为bellman_ford算法的起始点。
//这种方法可以处理非连通图。
//其次,spfa和bellman_ford默认1为起点是对的,
//因为field之间的path是双向的,只有wormholes之间是单向的,
//即只有负权路径是单向的,这种情况下只要图是连通的,任何一个点作为起点都可以!

  

posted on 2011-07-17 01:22  sysu_mjc  阅读(173)  评论(0编辑  收藏  举报

导航