hdu 2544(spfa)

10 篇文章 0 订阅
4 篇文章 0 订阅

    新学的spfa算法,

         spfa算法,就是利用更新的点来更新其他点。被更新的点,放在队列里面,当做其他点到源点的跳板,看看通过被更新的点是否可以缩短到源点的距离~~


   

#include <iostream>
#include <queue>
#include <cstdio>
const int size=99999999;
using namespace std;

int n,m;
int map[101][101];

int spfa(int s,int e)
{
  int low[101];
  bool vis[101];
  queue<int> q;
  
  for(int i=1;i<=n;i++)
   {
   	 vis[i]=false;  //入队列为true,不在队列为false. 
   	 low[i]=size;
   }	
  
  low[s]=0;
  vis[s]=true;    
  
  q.push(s);
  
  while(!q.empty())
  {
    int m=q.front();
	q.pop();
	
	vis[m]=false;
	
	for(int i=1;i<=n;i++)
	{
	  if(low[i]>low[m]+map[m][i])    // 通过m点来更新其他的点 
	   {
   		 low[i]=low[m]+map[m][i];
			
	     if(!vis[i]){           //因为i更新过,可以用来更新其他的点 
	         vis[i]=true;        //如果i不在队列里面,加入队列 
  		     q.push(i);
  	       }  
   	   } 	 
	  
	}	
  }
  
   return low[e]; 
}

int main()
{
  while(cin>>n>>m,m+n)
  {
  	int x,y,z;
    int sum;
    
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      map[i][j]=size;
      
	for(int i=0;i<m;i++)
	 {
 		//cin>>x>>y>>z;
 		scanf("%d%d%d",&x,&y,&z); 
	    map[x][y]=map[y][x]=z;
 	 }	

    sum=spfa(1,n);
	cout<<sum<<endl;     
     
  }	
	return 0;
}





SPFA算法(Shortest Path Faster Algorithm),也是求解单源最短路径问题的一种算法,用来解决:给定一个加权有向图G和源点s,对于图G中的任意一点v,求从s到v的最短路径。 SPFA算法是Bellman-Ford算法的一种队列实现,减少了不必要的冗余计算,他的基本算法和Bellman-Ford一样,并且用如下的方法改进:

 1、第二步,不是枚举所有节点,而是通过队列来进行优化 设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。 

2、同时除了通过判断队列是否为空来结束循环,还可以通过下面的方法:判断有无负环:如果某个点进入队列的次数超过V次则存在负环(SPFA无法处理带负环的图)。


#include <iostream>
#include <queue>
#include <cstdio>
const int size=99999999;
using namespace std;

int n,m;
int map[101][101];

int spfa(int s,int e)
{
  int low[101];
  int inque[101];  //入队的次数 
  bool vis[101];
  queue<int> q;

  memset(inque,0,sizeof(inque));  
  for(int i=1;i<=n;i++)
   {
   	 vis[i]=false;  //入队列为true,不在队列为false. 
   	 low[i]=size;
   }	
  
  low[s]=0;
  vis[s]=true;    
  inque[s]++;
  q.push(s);
  
  while(!q.empty())
  {
    int m=q.front();
	q.pop();
	
	vis[m]=false;
	
	for(int i=1;i<=n;i++)
	{
	  if(low[i]>low[m]+map[m][i])    // 通过m点来更新其他的点 
	   {
   		 low[i]=low[m]+map[m][i];
		
	     if(!vis[i]) {           //因为i更新过,可以用来更新其他的点 
	         vis[i]=true;        //如果i不在队列里面,加入队列 
             q.push(i);
  		     inque[i]++;
               if(inque[i]<n) continue;
               else  return -1;  //存在负边则输出 -1; 
  	       }  
   	   } 	 
	  
	}	
  }
  
   return low[e]; 
}

int main()
{
  while(cin>>n>>m,m+n)
  {
  	int x,y,z;
    int sum;
    
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      map[i][j]=size;
      
	for(int i=0;i<m;i++)
	 {
 		//cin>>x>>y>>z;
 		scanf("%d%d%d",&x,&y,&z); 
	    map[x][y]=map[y][x]=z;
 	 }	

    sum=spfa(1,n);
	cout<<sum<<endl;     
     
  }	
	return 0;
}


参考博客:http://www.cnblogs.com/devtang/archive/2011/08/25/spfa.html



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值