迪傑斯特拉初級練習

算法步驟:

(1)初始化:將源點S到圖中各點的直接距離最爲初始值記錄S到各點的最短距離,不能直接到達記作INF,S到本身的距離爲0。

(2)把所有其他除S的點放到集合B中,在所有集合B中遍歷一個到S的最短路徑距離的點u,並將其在集合B中取出。

(3)由新確定的u點更新S到集合B中一點v的距離爲最短。

(4)重複以上2、3兩個步驟。

基本思想:設置頂點集合S並不斷地作貪心選擇來擴充這個集合。一個頂點屬於集合S當且僅當從源到該頂點的最短路徑長度已知。初始時,S中僅含有源。設u是G的某一個頂點,把從源到u且中間只經過S中頂點的路稱爲從源到u的特殊路徑,並用數組dist記錄當前每個頂點所對應的最短特殊路徑長度。Dijkstra算法每次從V-S中取出具有最短特殊路長度的頂點u,將u添加到S中,同時對數組dist作必要的修改。一旦S包含了所有V中頂點,dist就記錄了從源到所有其它頂點之間的最短路徑長度。

時間複雜度:O(n*n)

空間複雜度(使用鄰接矩陣存儲時):O(n*n)

練習:

NYOJ:115

城市平亂

時間限制:1000 ms  |  內存限制:65535 KB
難度:4
描述

南將軍統領着N個部隊,這N個部隊分別駐紮在N個不同的城市。

他在用這N個部隊維護着M個城市的治安,這M個城市分別編號從1到M。

現在,小工軍師告訴南將軍,第K號城市發生了暴亂,南將軍從各個部隊都派遣了一個分隊沿最近路去往暴亂城市平亂。

現在已知在任意兩個城市之間的路行軍所需的時間,你作爲南將軍麾下最厲害的程序員,請你編寫一個程序來告訴南將軍第一個分隊到達叛亂城市所需的時間。

注意,兩個城市之間可能不只一條路。

輸入
第一行輸入一個整數T,表示測試數據的組數。(T<20)
每組測試數據的第一行是四個整數N,M,P,Q(1<=N<=100,N<=M<=1000,M-1<=P<=100000)其中N表示部隊數,M表示城市數,P表示城市之間的路的條數,Q表示發生暴亂的城市編號。
隨後的一行是N個整數,表示部隊所在城市的編號。
再之後的P行,每行有三個正整數,a,b,t(1<=a,b<=M,1<=t<=100),表示a,b之間的路如果行軍需要用時爲t

數據保證暴亂的城市是可達的。
輸出
對於每組測試數據,輸出第一支部隊到達叛亂城市時的時間。每組輸出佔一行
樣例輸入
1
3 8 9 8
1 2 3
1 2 1
2 3 2
1 4 2
2 5 3
3 6 2
4 7 1
5 7 3
5 8 2
6 8 2 
樣例輸出
4
來源
《世界大學生程序設計競賽高級教程·第一冊》改編
上傳者
張雲聰

代碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#define Max 1000005
#define N 1050
using namespace std;
int dis[N];
int map[N][N];
int vis[N];
int armycity[N];
void dijkstra(int query,int v)//要查詢的城市,節點數
{
    int i,j,k;

    for(i = 1; i <= v; i++)
    {
        dis[i] = map[query][i];//初始化,此處由於已經在之前處理過使得不能直接到達的點距離爲INF
    }
    dis[query] = 0;

    for(i = 1; i <= v-1; i++)//遍歷其它點到源點的最短路徑
    {
        int min = Max;
        k = 0;
        for(j = 1; j <= v; j++)//在集合U中選取一個到源點距離最小的點k。
        {
            if(!vis[j] && min > dis[j])
            {
                min = dis[j];
                k = j;
            }
        }
        if(k == 0)//沒有可以擴展的點
            return;
        vis[k] = 1;

        for(j = 1; j <= v; j++)//更新
        {
            if(dis[j] > dis[k] + map[k][j])
            {
                dis[j] = dis[k] + map[k][j];
            }
        }
    }
}
int main()
{
    int n,m,p,q;//部隊數、城市數(節點數)、城市之間路的條數(邊)、需要支援的節點。
    int a,b,c;
    int t;
    int i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d",&n,&m,&p,&q);
        for(i = 0; i < n; i++)
        {
            scanf("%d",&armycity[i]);
        }

        memset(map,Max,sizeof(map));
        memset(vis,0,sizeof(vis));

        for(i = 0; i < p; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(map[a][b] > c)
            {
                map[a][b] = c;
                map[b][a] = c;
            }
        }
        dijkstra(q,m);

        int ans = Max;
        for(i = 0; i < n; i++)
        {
            if(ans > dis[armycity[i]])
                ans = dis[armycity[i]];
        }
        printf("%d\n",ans);
    }
}



HDOJ 3790:

最短路徑問題

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9857 Accepted Submission(s): 3006


Problem Description
給你n個點,m條無向邊,每條邊都有長度d和花費p,給你起點s終點t,要求輸出起點到終點的最短距離及其花費,如果最短距離有多條路線,則輸出花費最少的。

Input
輸入n,m,點的編號是1~n,然後是m行,每行4個數 a,b,d,p,表示a和b之間有一條邊,且其長度爲d,花費爲p。最後一行是兩個數 s,t;起點s,終點。n和m爲0時輸入結束。
(1<n<=1000, 0<m<100000, s != t)

Output
輸出 一行有兩個數, 最短距離及其花費。

Sample Input
3 2 1 2 5 6 2 3 4 5 1 3 0 0

Sample Output
9 11
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAX 1000000
using namespace std;

int map[1005][1005];
int value[1005][1005];
int dis[1005];
int val[1005];
int vis[1005];

void dijkstra(int start,int n)
{
    int i,j,k,min;
    for(i = 1;i <= n; i++)
    {
        dis[i] = map[start][i];
        val[i] = value[start][i];
    }

    dis[start] = 0;
    val[start] = 0;

    for(i = 1; i <= n-1; i++)
    {
        min = MAX;
        k = 0;
        for(j = 1; j <= n; j++)
        {
            if(!vis[j] && min > dis[j])
            {
                min = dis[j];
                k = j;
            }
        }
        vis[k] = 1;
        if(k == 0)
            return;
        for(j = 1; j <= n; j++)
        {
            if(dis[j] > dis[k] + map[k][j])
            {
                dis[j] = dis[k] + map[k][j];
                val[j] = val[k] + value[k][j];
            }
            else if( dis[j] == dis[k]+map[k][j] && val[j] > val[k]+value[k][j] )
            {
                val[j] = val[k] + value[k][j];
            }
        }
    }
}

int main()
{
    int n,m;
    int i;
    int s,t;
    while(scanf("%d%d",&n,&m) && n+m)
    {
        int a,b,d,p;
        memset(vis,0,sizeof(vis));
        memset(map,MAX,sizeof(map));
        memset(value,MAX,sizeof(value));
        for(i = 0; i < m; i++)
        {
            scanf("%d%d%d%d",&a,&b,&d,&p);
            if(map[a][b] > d)//去重
            {
                map[a][b] = d;
                map[b][a] = d;
                value[a][b] = p;
                value[b][a] = p;
                //cout<<value[a][b]<<endl;
            }
        }
        scanf("%d%d",&s,&t);
        dijkstra(s,n);
        printf("%d %d\n",dis[t],val[t]);
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章