藍橋杯 單點最短路徑問題

 

剛看到題目的時候立刻就想到要用【鄰接矩陣】存儲邊,而且用 Dijkstra算法求最短路徑,可是提交代碼後,檢測結果是「運行錯誤」,內存使用很是大。算法

再從新看一遍題目,發現數據規模中節點數目的平方遠大於邊的數目,因此用鄰接矩陣存儲是很是浪費內存的。優化

查找相關課本,圖通常有四種存儲方式:spa

    一、鄰接矩陣:形式簡單,經常使用於節點數較少時,或者節點信息較少時,或是節點數的平方和邊的數目較爲相近時候。否在將耗費較大的空間資源。3d

    二、鄰接表:在邊稀疏或當和邊相關的信息較多時採用鄰接表存儲圖將會比鄰接矩陣節省存儲空間blog

    三、十字鏈表:結構相對前種複雜,通常用於有向圖遞歸

    四、臨界多重表:通常用於無向圖隊列

 

顯然,對於本題來講,採用鄰接表存儲圖是比較合理的。而且採用隊列以輔助尋找最短路徑。內存

 

#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;
}
相關文章
相關標籤/搜索