C++——spfa和dijkstra算法模板

题目背景

最短路模板题目。SPFA 或 用堆优化的迪杰斯特拉算法均可实现。

题目描述

成都浣花溪公园是一座有着诗歌文化气息的公园,它以杜甫草堂的历史文化内涵为背景,运用现代园林和建筑设计的前沿理论,以自然雅致的景观和建筑凸现川西文化醇厚的历史底蕴,是一座集将自然景观和城市景观、古典园林和现代建筑艺术有机结合的城市公园。

周末,Mr.Zeng和他儿子在浣花溪公园“诗歌大道”上欣赏诗歌,刚诗兴正浓,Mr.Zeng忽然想起汽车的车门没锁,于是他们要在最快的时间内走出公园赶到公园门口停车场。我们把公园的景点用数字标号(从1 到 N-1),在两个景点中之间会有道路连接,并且Mr.Zeng和他儿子都是素质很高的人,他们不会穿越公园的草坪,只会沿着公园的小路行走。Mr.Zeng想知道从他们当前所处的位置 S 到公园的出口(标号固定为 N)所需要的最短时间。你能帮帮他吗?

输入格式

输入文件的第一行有3 个正整数:N、K、T 并且用空格隔开,分别表示公园景点数目、公园小路条数,以及他们当前所处的景点编号。
接下来 K 行,每行三个整数,表示小路连接的两个景点的编号以及走过这条小路所需要的时间。

输出格式

一个整数,表示他们走出公园所需要的最短时间。

样例数据 1

输入

3 2 1 

1 2 3 

2 3 4

输出

7

备注

【数据范围】
对于 60% 的数据,保证 N<=1000,K<=10000。
对于 100% 的数据,保证 N<=10000,K<=100000。
对于 100% 的数据,保证结果在 231 内。

SPFA+Vector实现

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>

#include<vector>
#include<queue>            //p.push(t);    tmp=p.front();    p.pop();  

using namespace std;

struct node
       {
	       int to;          //to[i]表示第i条边的终点编号
	       int len;         //len[i]表示第i条边的权值
       }; 

vector <node> bian[200001]; //存储边,由于一般情况下E<<V*V,故在此选用了vector动态数组存储,也可以使用链表存储
queue <int> p;              //SPFA队列,用于存储在SPFA算法中的需要松弛的节点

int dist[10001];  
bool exist[10001];          //exist[i]=true表示点i已经在队列中
int n,k,t;                  //点数、变数、当前位置 

void init()                 //数据输入,建立邻接表   
{
    int i,x,y,w;
    freopen("park.in","r",stdin);
    freopen("park.out","w",stdout);

    scanf("%d%d%d",&n,&k,&t);       //点数、边数、当前位置t 
    
    for(i=1;i<=k;i++)
    {
        scanf("%d%d%d",&x,&y,&w);   //读入起始点、终点、权值
        
		node tmp;                   //设置一个临时变量,以便存入vector
		tmp.to=y;                   //设置边权
		tmp.len=w;                  //设置连接节点
		bian[x].push_back(tmp);     //将这条边压入x的表中
		
		tmp.to=x;                   //反向建边
		tmp.len=w;                  
    	bian[y].push_back(tmp);
	}
}

int main()   //主程序
{
   init();  //输入数据,
   memset(exist,false,sizeof(exist));
   for(int i=1;i<=n;i++)
       dist[i]=1000000000;            //初始化最短距离为一个较大的值,用memset(dis,127,sizeof(dis))求和可能溢出。 
   
   dist[t]=0;                         //起点的最短距离赋值为0
   p.push(t);                         //起点入队
   exist[t]=true;                     //标记起点已经入队

   while(!p.empty())                             //队列非空,需要继续松弛
   {
       int tmp=p.front();                         //取出队首元素 
	   exist[tmp]=false;                          //将队首节点标记为未入队
	   for(int i=0;i<(int)bian[tmp].size();i++)   //枚举该从tmp出发的每一条边
	   { 
			node *t=&bian[tmp][i];                  //由于vector的寻址速度较慢,故在此进行一次优化
			if(dist[tmp]+(*t).len < dist[(*t).to])  //更改后距离更短,进行松弛操作
            {  
				dist[(*t).to]=dist[tmp]+(*t).len;   //更改边权值
				if(!exist[(*t).to])                 //对面点没有入队,则将其入队
				{
					p.push((*t).to);       //将对面点压入队列
					exist[(*t).to]=true;   //标记对面点已经入队
				}
			}
       }
	   p.pop();              //弹出队首节点
	}

    printf("%d",dist[n]);   //输出到终点的最短路
    return 0;
}

二 纯dijkstra

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cctype>
using namespace std;
struct node{
	int w;
	int num;
};
node heap[10010];
int n,m,k,x,y,i,j,tot,cnt,z,p,s;
int next[200100],w[200100],v[200100],pl[10010],first[10010],dis[10010];
void addedge(int x,int y,int z)
{
	tot++;
	next[tot]=first[x];
	first[x]=tot;
	v[tot]=y;
	w[tot]=z;
}
void down(int x)
{
	int j;
	j=x<<1;
	while(j<=cnt)
	{
		if(j<cnt&&heap[j].w>heap[j+1].w) j++;
		if(heap[x].w<heap[j].w) break;
		else
		{
			swap(heap[x],heap[j]);
			pl[heap[x].num]=x;
			pl[heap[j].num]=j;
			x=j;
			j=j<<1;
		}
	}
}
void up(int x)
{
	int j;
	j=x>>1;
	while(j!=0&&heap[x].w<heap[j].w)
	{
		swap(heap[x],heap[j]);
		pl[heap[x].num]=x;
		pl[heap[j].num]=j;
		x=j;
		j=j>>1;
	}
}
int main()
{
	//freopen("hhxgy.in","r",stdin);
	scanf("%d%d%d",&n,&m,&s);
	tot=0;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		 addedge(x,y,z);
		 addedge(y,x,z);
	}
	memset(dis,127,sizeof(dis));
	dis[s]=0;
	cnt=0;
	for(i=1;i<=n;i++)
	{
		cnt++;
		heap[cnt].w=1E+9;
		heap[cnt].num=i;
		pl[i]=cnt;
	}
	heap[pl[s]].w=0;
	up(pl[s]);
	for(i=1;i<=n;i++)
	{
		j=heap[1].num;
		heap[1]=heap[cnt];
		cnt--;
		down(1);
		p=first[j];
		while(p>0)
		{
			if(dis[j]+w[p]<dis[v[p]])
			{
				dis[v[p]]=dis[j]+w[p];
				heap[pl[v[p]]].w=dis[v[p]];
				up(pl[v[p]]);
			}
			p=next[p];
		}
	}
	printf("%d",dis[n]);
	return 0;
}

三 dijkstra+优先队列优化

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#include<queue>


using namespace std;


int n,m,t,x,y,z,tot;
int first[10010],dis[10010];
bool exist[10010];
pair<int,int> temp;


struct node
{
	int next;
	int to;
	int w;
}edge[200010];


inline void create(int x,int y,int z)
{
	tot++;
	edge[tot].next=first[x];
	first[x]=tot;
	edge[tot].to=y;
	edge[tot].w=z;
}


void read(void)
{
	cin>>n>>m>>t;
	for(int i=1;i<=m;++i)
	{
		cin>>x>>y>>z;
		create(x,y,z);
		create(y,x,z);
	}
}


int dijkstra(int s,int t)
{
	priority_queue<pair <int,int> >q;
	memset(dis,110,sizeof(dis));
	dis[s]=0;
	temp.first=0;
	temp.second=s;
	q.push(temp);
	while(!q.empty())
	{
		temp=q.top();
		q.pop();
		exist[temp.second]=true;
		int p=first[temp.second];
		int j=temp.second;
		while(p>0)
		{
			if(!exist[edge[p].to]&&dis[edge[p].to]>dis[j]+edge[p].w)
			{
				dis[edge[p].to]=dis[j]+edge[p].w;
				pair<int,int> s;
				s.first=-dis[edge[p].to];
				s.second=edge[p].to;
				q.push(s);
			}
			p=edge[p].next;
		}
	 } 
	 return dis[t];
}


int main()
{
	read();
	cout<<dijkstra(t,n);
	return 0;
}

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/McDonnell_Douglas/article/details/54379641
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞