首页 > 代码库 > 蓝桥杯 单点最短路径问题

蓝桥杯 单点最短路径问题

技术分享

 

刚看到题目的时候马上就想到要用【邻接矩阵】存储边,并且用 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=http://www.mamicode.com/i;"%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;
}

蓝桥杯 单点最短路径问题