Bellman-Ford && SPFA

   作为最短路的其他几种解法,是很有必要掌握的,已知的Dijkstra只能够解决不存在负权边的图形(其灵魂是在确定点的时候同时预言了其后面一定是大于零的边),而 Floyed 算法的时间复杂度决定了其使用的范围。所以在遇到负权边的时候就要用到Bellman-Ford或者是SPFA了,可以说其是对于 Dijkstra 算法的一个简化,没有了寻找最小路径长度点然后加入集合的过程。Bellman每次都暴力搜索所有顶点,直到没有点再被更新为止,SPFA遇到更新的点就加入队列,直到队列为空为止,当然也可以使用栈。

  这是写的两个简单的程序:

// Bellman-Ford
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#define INF 0x7f7f7f7f
using namespace std;

struct Node
{
	int pos;
	int dis;
}info;

int dis[1001], path[1001];

bool Bellman_Ford( int N, int M, vector< Node >vec[] )
{
	vector< Node >::iterator it;
	for( int i= 1; i<= N; ++i )
	{
		dis[i]= INF;
		path[i]= -1;
	}
	dis[0]= 0;
	for( int i= 1; i<= M; ++i )
	{
		bool finish= true;
		for( int j= 0; j< N; ++j )
		{
			for( it= vec[j].begin(); it!= vec[j].end(); ++it )
			{
				if( dis[j]> dis[ it->pos ]+ it->dis )
				{
					finish= false;   //  这时由于每次如果有边进行更新的话,那么其可能为其他边提供更好的路径
					dis[j]= dis[ it->pos ]+ it->dis;
					path[j]= it->pos;
				}
			}
		}  // 接下来是判定是否有负环的存在,如果存在负环,那么将提供一条路径使得接触到该环的所有点的距离变成无群小,这显然不和题义
           // 证明其并不是在真正意义上按照边数递增的原则来更新边
		if( finish )
		{
			return true;
		}
	}
	for( int j= 1; j<= N; ++j )
	{
		for( it= vec[j].begin(); it!= vec[j].end(); ++it )
		{
			if( dis[j]> dis[ it->pos ]+ it->dis )
			{
				return false;
			}
		}
	}
}

int main(  )
{
	int N, M;
	while( scanf( "%d %d", &N, &M ), N| M )
	{
		vector< Node >vec[1001];
		for( int i= 2; i<= N; ++i )
		{
			int x, y, z;
			scanf( "%d %d %d", &x, &y, &z );
			info.pos= x- 1, info.dis= z;
			vec[y- 1].push_back( info );  // 这里需要建立一个逆邻接表
			info.pos= y- 1;
			vec[x- 1].push_back( info );
		}
		Bellman_Ford( N, M, vec );
	/*	if( Bellman_Ford( N, M, vec ) )
		{
			for( int i= 0; i< N; ++i )
			{
				printf( "The shortest path to vertex 1 for vertex %d is %d\n", i, dis[i] );
			}
			for( int i= 0; i< N; ++i )
			{
				printf( "path[%d]= %d\n", i, path[i] );
			}
		}
		else
		{
			puts( "No shortest path exsit!" );
		} */
		printf( "%d\n", dis[N- 1] );
	}
	
}
// SPFA
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
#define INF 0x7f7f7f7f
using namespace std;

struct Node
{
	int pos, dis;
}info;

int dis[1001], path[1001], ti[1005], inqu[1005];

bool SPFA( int N, int M, vector< Node >vec[] )
{
	vector< Node >::iterator it;
	for( int i= 0; i< N; ++i )
	{
		dis[i]= INF;
		inqu[i]= 0;
		ti[i]= 0;
	}
	dis[0]= 0;
	queue< int >q;
	q.push( 0 );
	inqu[0]= 1;
	while( !q.empty() )
	{
		int pos= q.front();
		q.pop();
		inqu[pos]= 0;
		for( it= vec[pos].begin(); it!= vec[pos].end(); ++it )
		{
			if( dis[ it->pos ]> dis[ pos ]+ it->dis )
			{
				dis[ it->pos ]= dis[ pos ]+ it->dis;
				// 在其基础上还需加上一个是否已在队列中的一个判断以及判定是否入队次数已经超过N次(是否产生负向环)
				// 如果已经在队列中则没有必要再将其入队,如果继续入队的话,就算是重复更新了
				if( !inqu[ it->pos ] )
				{
				    q.push( it->pos );
				    ti[ it->pos ]++;
				    if( ti[ it->pos ]> N )
				    {
				        return false;
				    }
			    }
			}
		}
	}
	return true;
}

int main()
{
	int N, M;
	while( scanf( "%d %d", &N, &M ), N| M )
	{
	    vector< Node >vec[1001];
		for( int i= 1; i<= M; ++i )
		{
			int x, y, z;
			scanf( "%d %d %d", &x, &y, &z );
			info.pos= y- 1, info.dis= z;
			vec[x- 1].push_back( info );  // 这里采用的是一般的邻接表,而非bellman_ford中的逆邻接表,原因是该算法是主动性更新的
			info.pos= x- 1;
			vec[y- 1].push_back( info );
		}
		SPFA( N, M, vec );
/*		for( int i= 0; i< N; ++i )
		{
			printf( "dis[%d]= %d\n", i, dis[i] );
		}  */
		printf( "%d\n", dis[N- 1] );
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值