zoukankan      html  css  js  c++  java
  • BellmanFord && 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] );
    	}
    }
    
  • 相关阅读:
    移动硬盘加密方法赏析
    Windows7下怎么对文件或者文件夹进行EFS加密
    win7怎么设置电脑自动关机
    电脑定时关机怎么设置
    用vb编程给u盘加密
    中医课件集合
    在手机上查询药品信息?PEP移动掌上药物信息参考
    【好站收藏】六脉医学资料下载网sixmed.cn
    百度进军C2C叫板淘宝电子商务领域竞争升级
    IBM 笔记本T43键盘帽安装手记
  • 原文地址:https://www.cnblogs.com/Lyush/p/2128714.html
Copyright © 2011-2022 走看看