1. 程式人生 > >圖結構練習——最短路徑(Dijkstra演算法)

圖結構練習——最短路徑(Dijkstra演算法)

think:
1注意重複邊的覆蓋
2注意map陣列的初始化
3注意dist陣列的初始化

圖結構練習——最短路徑
Time Limit: 1000MS Memory Limit: 65536KB

Problem Description
給定一個帶權無向圖,求節點1到節點n的最短路徑。

Input
輸入包含多組資料,格式如下。
第一行包括兩個整數n m,代表節點個數和邊的個數。(n<=100)
剩下m行每行3個正整數a b c,代表節點a和節點b之間有一條邊,權值為c。

Output
每組輸出佔一行,僅輸出從1到n的最短路徑權值。(保證最短路徑存在)

Example Input
3 2
1 2 1
1 3 1
1 0

Example Output
1
0

Hint

Author
趙利強

以下為accepted程式碼

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

#define INF  0x3f3f3f3f
int n, m;
int map[104][104], vis[104], dist[104];

void Dijkstra(int v)
{
    int i, j, k;
    for(i = 1; i <= n; i++)//dist陣列的初始化
{ dist[i] = map[v][i]; vis[i] = 0; } dist[v] = 0; vis[v] = 1; for(i = 0; i < n-1; i++) { int min = INF, u = v; for(j = 1; j <= n; j++)//尋找未標記結點的最小值 { if(vis[j] == 0 && dist[j] < min) { u = j; min = dist[j]; } } vis[u] = 1
; for(k = 1; k <= n; k++)//更新最短路 { if(vis[k] == 0 && map[u][k] < INF && dist[k] > dist[u] + map[u][k]) { dist[k] = dist[u] + map[u][k]; } } } } int main() { int i, j, a, b, c; while(scanf("%d %d", &n, &m) != EOF) { memset(vis, 0, sizeof(vis)); for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { if(i == j) map[i][j] = 0; else map[i][j] = INF; } } for(i = 0; i < m; i++) { scanf("%d %d %d", &a, &b, &c); if(map[a][b] > c)///避免覆蓋最短路 map[a][b] = map[b][a] = c; } if(m == 0) printf("0\n"); else { Dijkstra(1); printf("%d\n", dist[n]); } } return 0; } /*************************************************** User name: Result: Accepted Take time: 12ms Take Memory: 208KB Submit time: 2017-02-17 19:30:41 ****************************************************/

以下為wrong answer程式碼——Dijkstra演算法理解不紮實,導致變數位置使用錯誤(將u的位置寫成了v)

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

#define INF  0x3f3f3f3f
int n, m;
int map[104][104], vis[104], dist[104];

void Dijkstra(int v)
{
    int i, j, k;
    for(i = 1; i <= n; i++)//dist陣列的初始化
    {
        dist[i] = map[v][i];
        vis[i] = 0;
    }
    dist[v] = 0;
    vis[v] = 1;

    for(i = 0; i < n-1; i++)
    {
        int min = INF, u = v;
        for(j = 1; j <= n; j++)//尋找未標記結點的最小值
        {
            if(vis[j] == 0 && dist[j] < min)
            {
                u = j;
                min = dist[j];
            }
        }
        vis[u] = 1;

        for(k = 1; k <= n; k++)//更新最短路
        {
            if(vis[k] == 0 && map[v][k] < INF && dist[k] > dist[u] + map[u][v])
            {
                dist[k] = dist[u] + map[u][k];
            }
        }
    }
}
int main()
{
    int i, j, a, b, c;
    while(scanf("%d %d", &n, &m) != EOF)
    {
        memset(vis, 0, sizeof(vis));
        for(i = 1; i <= n; i++)
        {
            for(j = 1; j <= n; j++)
            {
                if(i == j)
                    map[i][j] = 0;
                else
                    map[i][j] = INF;
            }
        }
        for(i = 0; i < m; i++)
        {
            scanf("%d %d %d", &a, &b, &c);
            if(map[a][b] > c)///避免覆蓋最短路
                map[a][b] = map[b][a] = c;
        }
        if(m == 0)
            printf("0\n");
        else
        {
            Dijkstra(1);
            printf("%d\n", dist[n]);
        }

    }
    return 0;
}


/***************************************************
User name: 
Result: Wrong Answer
Take time: 16ms
Take Memory: 208KB
Submit time: 2017-02-17 19:27:15
****************************************************/

以下為wrong answer程式碼——
1 沒有考慮到重複邊的覆蓋問題
2 map陣列初始化錯誤

#include <stdio.h>
#include <string.h>
#define INF 9999999
int n, m;
int map[104][104], dist[10400], vis[10400];
void Dijkstra(int v)
{
    for(int i = 1; i <= n; i++)
    {
        dist[i] = map[v][i];
        vis[i] = 0;
    }
    vis[v] = 1;
    dist[v] = 0;
    for(int i = 0; i < n-1; i++)
    {
        int min = INF, u = v;
        for(int j = 1; j <= n; j++)//尋找未訪問的結點中的最小值
        {
            if(vis[j] == 0 && dist[j] < min)
            {
                u = j;
                min =dist[j];
            }
        }
        vis[u] = 1;

        for(int k = 1; k <= n; k++)//更新
        {
            if(vis[k] == 0 && map[u][k] < INF && dist[k] > dist[u] + map[u][k])
            {
                dist[k] = dist[u] + map[u][k];
            }
        }
    }
}
int main()
{
    int a, b, c;
    while(scanf("%d %d", &n, &m) != EOF)
    {
        memset(map, 0, sizeof(map));
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i < m; i++)
        {
            scanf("%d %d %d", &a, &b, &c);
            map[a][b] = c;
        }
        Dijkstra(1);
        printf("%d\n", dist[n]);
    }
    return 0;
}


/***************************************************
User name: 
Result: Wrong Answer
Take time: 12ms
Take Memory: 192KB
Submit time: 2017-02-17 18:41:44
****************************************************/