蓝桥杯——图的3种存储方式

  • 邻接矩阵
    采用一个二维数组d[i][j]来存储图,d[i][j]一般为i点和j点之间的距离或是连接关系
  • 邻接链表
    用链表的方式存储图,节约了空间。基本思路是每个节点作为一个链表的头,对于n个节点我们会构造n条链表。一条链表上除头节点外的其他节点,表示与头节点的相邻节点
  • 链式前向星
    求最短路径时的一种加速的数据结构,本质是用数组表示邻接链表。主要有两个核心的数据结构:
int head[N];

head[i]表示节点i对应的边的编号,例如head[i]=cnt表示i号节点对应cnt号边

struct Edge{
	int next=0;	//next表示下一个边的编号,即兄弟边
	int to=0;	//to表示作为终点的节点的编号
	int w;		//w表示权重
}edge[N];

head[i]=cnt表示节点i有一条第cnt号边edge[cnt],这条边为i->edge[cnt].to,长度为edge[cnt].w;i号节点同时还有一条邻边edge[cnt].next,邻边为i->edge[edge[cnt].next].to

  • 遍历节点i的所有邻边
cnt=head[i]
while(cnt!=0){
	printf("%d->%d	w:%d",i,edge[cnt].to,edge[cnt].w);
	cnt=edge[cnt].next;
}
  • 添加边
//这一步相当于在链表中插入一个新节点
void addEdge(int u,int v,int w){
	cnt++;
	//确定终点
	edge[cnt].v=v;
	//确定权重
	edge[cnt].w=w;
	//插入节点
	edge[cnt].next=head[u];
	head[u]=cnt;
}

链式前向星本质就是一个邻接链表

  • 链式前向星+堆优化+dijkstra
#include<iostream>
#include<bits/stdc++.h>
#include <queue>
using namespace std;
const int N=1e5+9;
const int MAXEDGE=5e5+9;
const long long int MAXNUM=0x7fffffff;
int n,m,s;
long long int d[N];
bool flag[N];
//链式前向星
int head[N];
long long int cnt=0;
struct Edge{
	long long int next;
	long long int to;
	long long int w;
}edge[MAXEDGE];
void addEdge(long long int u,long long int v,long long int w){
	cnt++;
	//构造边 
	edge[cnt].to=v;
	edge[cnt].w=w;
	edge[cnt].next=head[u];
	head[u]=cnt;
}
int main(){
	cin>>n>>m>>s;
	//初始化距离
	for(int i=1;i<=n;i++){
		d[i]=MAXNUM;
		flag[i]=false;
		head[i]=0;
	}
	//堆优化 
	d[s]=0;
	priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> minHeap;
	minHeap.push(pair<int,int>(0,s));
	
	//构造前向星(本质上是邻接链表)
	long long u,v,w;
	for(int i=1;i<=m;i++){
		cin>>u>>v>>w;
		addEdge(u,v,w);
	} 
	
	//dijkstra算法
	//采用堆优化时必须用堆空作为循环结束条件,因为堆中会有重复的节点 
	while(!minHeap.empty()){
		 
		//寻找距离s最近的点
		int k=minHeap.top().second; 
		minHeap.pop();
		//先判断k是否访问过
		if(flag[k]==true)	continue;
		flag[k]=true;
		//进行松弛
		for(int j=head[k];j!=0;j=edge[j].next){
			if(flag[edge[j].to]==false&&d[edge[j].to]>d[k]+edge[j].w){
				d[edge[j].to]=d[k]+edge[j].w;
				//压入堆
				minHeap.push(pair<int,int>(d[edge[j].to],edge[j].to));		
			}
		} 
	} 
	for(int i=1;i<=n;i++){
		cout<<d[i]<<" ";
	}
	return 0;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值