蓝桥杯 单点最短路径问题

刚看到题目的时候马上就想到要用【邻接矩阵】存储边,并且用 Dijkstra算法求最短路径,但是提交代码后,检测结果是“运行错误”,内存使用非常大。

再重新看一遍题目,发现数据规模中节点数目的平方远大于边的数目,所以用邻接矩阵存储是非常浪费内存的。

查找相关课本,图一般有四种存储方式:

    1、邻接矩阵:形式简单,常用于节点数较少时,或者节点信息较少时,或是节点数的平方和边的数目较为相近时候。否在将耗费较大的空间资源。

    2、邻接表:在边稀疏或当和边相关的信息较多时采用邻接表存储图将会比邻接矩阵节省存储空间

    3、十字链表:结构相对前种复杂,一般用于有向图

    4、临界多重表:一般用于无向图

显然,对于本题来说,采用邻接表存储图是比较合理的。并且采用队列以辅助寻找最短路径。

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
const int maxsize=200000;
const int inf = 1000000;

//边节点
typedef struct XNode
{
	int pow;
	int adjvex;
	struct XNode* next;
}Node;

Node* head[maxsize];//头节点
int visit[maxsize],dist[maxsize];

//添加边
void AddAdj(int u,int v,int l)
{
	Node *p;
	p = (Node*)malloc(sizeof(Node));
	p->pow=l;
	p->adjvex=v;
	p->next=head[u]->next;
	head[u]->next=p;
} 

//求最短路径
void shortpath(int n)
{
	int i,j,u,v,w;
	queue<int> Q;
	Node *p;
	for(i=1;i<=n;i++)
	{
		visit[i]=0;
		dist[i]=inf;
	}

	//第一个节点入队列
	Q.push(1);
	dist[1]=0;
	visit[1]=1;

	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();
                //求与定点u邻接的所有顶点的最短路径
		for(p=head[u]->next;p!=NULL;p=p->next)
		{
			v=p->adjvex;
			w=p->pow;
			if(dist[u]+w<dist[v])
			{
				dist[v]=dist[u]+w;//过点u到达v的路径比原路径短
				if(!visit[v])//若节点未被访问过
				{
					visit[v]=1;
					Q.push(v);
				}
			}
		}
	}

}

int main()
{
	int n,m,u,v,w;

	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n;i++)//初始化头结点
	{
		head[i]=(Node*)malloc(sizeof(Node));
		head[i]->next=NULL;
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		AddAdj(u,v,w);
	}

	shortpath(n);
	for(i=2;i<=n;i++)
		printf("%d\n",dist[i]);

	return 0;
}

优化改进后的通用代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
using namespace std;

const int MaxSize = 100000;
const int Inf = 10000;//无穷大定义 

//边节点定义
typedef struct XNode
{
	int asc,pow;
	XNode* next;
}Node;

//头节点定义
typedef struct XHead
{
	int data;	//顶点标识
	int pre;	//最短路径中的前一个节点下标
	Node* firstvex;
}Head;

Head head[MaxSize];
int dist[MaxSize],visit[MaxSize],path[MaxSize];

//添加边
void InserAsc(int u,int v,int w)
{
	Node* p;
	p=(Node*)malloc(sizeof(Node));
	if(!p)exit(-1);
	p->asc=v;
	p->pow=w;
	p->next=head[u].firstvex;
	head[u].firstvex=p;
}

//求节点总数为n,的顶点vex到其余各点的最短路径
void Dijstr(int n,int vex)
{
	int i,j;
	queue<int> Q;
	//初始化
	for(i=1;i<=n;i++)
	{
		dist[i]=Inf;
		visit[i]=0;
		path[i]=0;
		head[i].pre=0;
	}

	int u,v,w,k;
	Node* p;
	visit[vex]=1;
	dist[vex]=0;
	k=0;
	Q.push(vex);
	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();
		for(p=head[u].firstvex;p!=NULL;p=p->next)
		{
			v=p->asc;
			w=p->pow;
			if(dist[u]+w<dist[v])
			{
				dist[v]=dist[u]+w;
				head[v].pre=u;
				if(visit[v]==0)
				{
					Q.push(v);
					visit[v]=1;
				}
			}
		}
	}

}

//递归显示点v1到点v2的最短路径
void displaypath(int v1,int v2)
{
	if(v2==0)return;
	else if(v2==v1)
	{
		printf("%d ",v1);
	}
	else
	{
		displaypath(v1,head[v2].pre);
		printf("%d ",v2);
	}
}

int main()
{
	int i,j,n,m,u,v,w;

	scanf("%d%d",&n,&m);

	for(i=1;i<=n;i++)
	{
		head[i].data=i;
		head[i].firstvex=(Node*)malloc(sizeof(Node));
		head[i].firstvex=NULL;
	}

	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&u,&v,&w);
		InserAsc(u,v,w);
	}

	int vex;
	printf("请输入源点:");
	scanf("%d",&vex);
	Dijstr(n,vex);

	printf("点%d到其余各点的最短距离:\n",1);
	for(i=1;i<=n;i++)
	{
		if(dist[i]!=Inf)printf("%d\n",dist[i]);
		else printf("Inf\n");
	}
	printf("最短路径:\n");
	for(i=1;i<=n;i++)
	{
		if(i==vex)continue;
		printf("点%d到点%d的最短路径:\n",1,i);
		displaypath(vex,i);
		printf("\n");
	}

	return 0;
}
时间: 2024-08-04 22:32:27

蓝桥杯 单点最短路径问题的相关文章

第四届蓝桥杯 c/c++真题

第四届蓝桥杯 c/c++真题 <1>高斯日记 问题 大数学家高斯有个好习惯:无论如何都要记日记. 他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210 后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天.这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢? 高斯出生于:1777年4月30日. 在高斯发现的一个重要定理的日记上标注着:5343,因此可算出那天是:1791年12月15日. 高斯获得博士学位的那天日记上标着:

蓝桥杯 2014本科C++ B组 奇怪的分式 暴力枚举

蓝桥杯 枚举 奇怪的分式 标题:奇怪的分式 上小学的时候,小明经常自己发明新算法.一次,老师出的题目是: 1/4 乘以 8/5 小明居然把分子拼接在一起,分母拼接在一起,答案是:18/45 (参见图1.png) 老师刚想批评他,转念一想,这个答案凑巧也对啊,真是见鬼! 对于分子.分母都是 1~9 中的一位数的情况,还有哪些算式可以这样计算呢? 请写出所有不同算式的个数(包括题中举例的). 显然,交换分子分母后,例如:4/1 乘以 5/8 是满足要求的,这算做不同的算式. 但对于分子分母相同的情况

2015第六届蓝桥杯竞赛感悟

之前对算法一直是敬畏的,觉得很难去学习,但是通过蓝桥杯竞赛也算是强迫自己认真学习了一个多月的算法,发现算法也是可以学的. 前天竞赛就结束了,一直拖到今天才来写一篇总结,其实这次竞赛收货真的蛮大的,自己以前一直不够重视内功的培养,现在能有这么一个机会来修炼内容还是挺开心的. 感觉这次考试题和前两届去比确实难度有所增加,第九题缓存没有写好,第十题压根就没来的及做...其实第十题下来想想是能做的,只是考前最短路径这种动态规划题做的不多,所以在比赛场上就有点怯了...虽然是很想得一等奖参加决赛的,不过照

蓝桥杯 最短路 道路和航路 SPFA算法

1.SPFA算法 算法训练 最短路 时间限制:1.0s   内存限制:256.0MB 锦囊1 使用最短路算法. 锦囊2 使用Dijkstra算法,此图的边数比点数的平方要少很多,因此应该使用带堆优化的Dijkstra. 问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环).请你计算从1号点到其他点的最短路(顶点从1到n编号). 输入格式 第一行两个整数n, m. 接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边. 输出格式 共n-1行,第i行

蓝桥杯-最短路 (SPFA算法学习)

SPFA算法主要用来解决存在负边权的单源最短路情况(但不能有负环!!!)一个简单的方法判断是否有没有负环可以通过判断是否有一个节点是否频繁进出队列. 以下内容转自https://blog.csdn.net/xunalove/article/details/70045815 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm. SPFA算法是西南交通大学段凡丁于1994年发表的. 从名字我们就可以看出,这种算法在效率上一定有过人之处. 很多时候,给定的

2015年蓝桥杯省赛B组C/C++(试题+答案)

首先说,这次我是第二次参加蓝桥杯(大学里最后一次),可这次去连个三等都没拿到,有些心灰意冷,比上一次还差, 当时看到成绩出来的时候有些失落,但是跌倒了,再站起来继续跑就可以了.可能是状态不好吧,纯属自我安慰. 接下来我把今年的题目又重新做了一遍,写下了这篇博客,如果也有需要探讨答案的,希望可以有帮助. 第一题: 第1题:统计不含4的数字 题目大意 统计10000至99999中,不包含4的数值个数. 解题分析: 第一种解法: 数学方法,这种是在网上看到的一种解法: 最高位除了0.4不能使用,其余8

蓝桥杯——算法训练之乘积最大

问题描述 今年是国际数学联盟确定的"2000--世界数学年",又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加.活动中,主持人给所有参加活动的选手出了这样一道题目: 设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大. 同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子: 有一个数字串:312, 当N=3,K=1时

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

蓝桥杯——判定字符的位置。

蓝桥杯——判断字符的位置 题目: 输入一个字符串,编写程序输出该字符串中元音字母的首次出现位置,如果没有元音字母输出0.英语元音字母只有‘a’.‘e’.‘i’.‘o’.‘u’五个. 样例输入: hello样例输出:2 样例输入: apple样例输出:1 样例输入: pmp样例输出:0 java code: import java.util.*;public class Yuanyingzifu {    public static int fun(String str)    {