C++之路進階——優先隊列優化最短路徑算法(dijkstra)


一般的dijkstra算法利用貪心的思想,每次找出最短邊,然后優化到其他點的的距離,我們還采用貪心思路,但在尋找最短邊進行優化,之前是雙重for循環,現在我們用優先隊列來實現。

代碼解釋:

//樣例程序采用邊表儲存。   

#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
#include<iostream>

using namespace std;

int head[100000]={0},next[200000]={0},aa[200000]={0},size,s,tt,m,n;


struct bb
{
int x,y;
}a[100000];//記錄點的橫縱坐標。
double val[100000],dis[100000]={0};


void add(int h,int t,double c)//建立邊表。
{
size++;//對邊進行重編號。
next[size]=head[h];
head[h]=size;
aa[size]=t;
val[size]=c;
}

void init()
{
scanf("%d",&n);
for (int i=0;i<n;i++)
{
int u,v;
double c;
scanf("%d%d",&u,&v); //讀入有邊的兩點。
c=sqrt((a[u-1].x-a[v-1].x)*(a[u-1].x-a[v-1].x)+(a[u-1].y-a[v-1].y)*(a[u-1].y-a[v-1].y));//用數學公式求出兩點間距離。
add(u,v,c);//建立由u到v的邊,權值為c;
add(v,u,c);//若圖為有向圖,則省略該語句。
}
scanf("%d%d",&s,&tt); //讀入所求的由s到tt的距離。目標。
}

void initint()//存下點的坐標。
{
scanf("%d",&m);
for (int i=0;i<m;i++)
scanf("%d%d",&a[i].x,&a[i].y);
}

struct ss//定義優先隊列的自定義結構體。
{
int x;
double y;
ss(){}//定義構造函數。
ss(int xx,double yy)//重載該函數。
{
x=xx;
y=yy;
}


bool operator<(const ss& b)const//重載<運算符(因為我們要找最小值,而優先隊列默認為大根堆)。
{
return y>b.y;
}
};

void dij()//dijkstra算法
{
priority_queue<ss>que;//定義優先隊列,不懂看“C++之路啟航——標准模板庫(queue)”
que.push(ss(s,0));//把起點壓入隊列中。
for (int i=0;i<=m;i++)//
dis[i]=100000000;
dis[s]=0;// 初始操作。
while (!que.empty())
{
ss op=que.top();//取出最小值。op.x為點的編號,op.y為從起點到該點的距離。
que.pop();
if (op.y>dis[op.x]) continue;//一步優化。
for (int i=head[op.x];i!=0;i=next[i]) //遍歷與該點相連的邊。
{
int j=aa[i];
if (dis[j]>dis[op.x]+val[i])//找到能夠更新的,並且壓入隊列中。
{
dis[j]=dis[op.x]+val[i];
que.push(ss(j,dis[j]));
}
}
}
printf("%.2f",dis[tt]);//輸出;
return;
}

int main()
{
initint();
init();
dij();
return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM