单源最短路径问题(狄克斯特拉算法)

挑战程序设计竞赛2上的一道例题
P250

#include<iostream>
using namespace std;
static const int MAX = 100;
static const int INFTY = (1<<21); /这里表示int类型最大值
static const int WHITE = 0;//表示三种状态
static const int GRAY = 1;
static const int BLACK = 2;
//点的个数和邻接矩阵存储方式
int n, M[MAX][MAX];

void dijkstra()
{
	int minv;
	//最短路径和每个点状态的存储结构
	int d[MAX], color[MAX];
	//初始化
	for(int i = 0; i < n; i++)
	{
		d[i] = INFTY;
		color[i] = WHITE;
	}
	//从零开始到每个点的最短路径
	d[0] = 0;
	color[0] = GRAY;
	//不断循环直至所有点包含在内即color[i]的状态全为BLACK
	while(1)
	{
		minv = INFTY;
		int u = -1;
    //求出距离0点最短路径并记录下标
		for( int i = 0; i < n; i++ )
		{
			if(minv > d[i] && color[i] != BLACK)
			{
				u = i;
				minv = d[i];
			}
		}
		//状态全为BLACK结束循环
		if(u == -1) break;
		color[u] = BLACK;
		//更新到每个点的最短路径d[i]
		for(int v = 0; v < n; v++)
		{
			if(color[v] != BLACK && M[u][v] != INFTY)
			{
				if(d[v] > d[u] + M[u][v])
				{
					d[v] = d[u] + M[u][v];
					color[v] = GRAY;
				}
			}
		}
	}
	//按要求输出
	for (int i = 0; i < n; i++ )
	{
		cout<< i <<" "<<(d[i] == INFTY ? -1: d[i]) << endl; 
	}
}

int main()
{
	cin>>n;
	//初始化邻接矩阵
	for( int i = 0; i < n; i++ )
	{
		for( int j = 0; j < n; j++ )
		{
			M[i][j] = INFTY;
		}
	}
	
	int k, c, u, v;
	for( int i = 0; i < n; i++ )
	{
		cin >> u >> k;
		for( int j = 0; j < k; j++)
		{
			cin>>v>>c;
			M[u][v] = c;
		}
	}
	dijkstra();
	
	return 0;
}

本算法不具有代表性,狄克斯特拉算法模板还有待更新,这pain文章还会继续更新…

一月十二日更新
spfa算法
题目链接点我

  • SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环。SPFA最坏情况下复杂度和朴素 Bellman-Ford 相同,为 O(VE)。
  • 可作为基础模板的代码如下:
#include<bits/stdc++.h>
const int inf=(1<<20);
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,cnt=0;
//head[u],u是指点的编号,head[u]的值是与u邻接的边的编号 
int dis[maxn],vis[maxn],head[maxm];

struct Edge
{
  int next,to,dis;//上一条边的编号,本结点的编号,本条边的权值 
}edge[maxm]; //结构体表示静态邻接表
void add(int from,int to,int dis) //邻接表建图
{ //以下是链式前向星存图的标准代码
  edge[++cnt].next=head[from]; //链式存储下一条出边
  edge[cnt].to=to; //当前节点编号
  edge[cnt].dis=dis; //本条边的权值 
  head[from]=cnt; //记录下一次的出边情况
}
void spfa()
{
  queue<int> q; //spfa用队列,这里用了STL的标准队列
  for(int i=1; i<=n; i++) 
  {
    dis[i]=inf; //带权图初始化
    vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
  }
  q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
  while(!q.empty())
  {
    int u=q.front(); //取出队首
    q.pop(); vis[u]=0; //出队标记,这里必须出队因为本算法是对所有邻接点到其他点的距离做更换 
    for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
    {
      int v=edge[i].to; 
      if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
      {
        dis[v]=dis[u]+edge[i].dis;
        if(vis[v]==0) //未入队则入队
        {
          vis[v]=1; //标记入队
          q.push(v);
        }
      }
    }
  }
}
int main()
{
	cout<<inf<<endl;
  cin>>n>>m>>s;//n个点,m条边,s为开始顶点 
  for(int i=1; i<=m; i++)
  {
    int f,g,w;
    cin>>f>>g>>w; 
    add(f,g,w); //建图,有向图连一次边就可以了
  }
  spfa(); //开始跑spfa
  for(int i=1; i<=n; i++)
    if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
      else cout<<dis[i]<<" "; //否则打印最短距离
  return 0;
} //结束

链式前向星存图方法看上一篇文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值