Bài thực hành 3

Trong bài này bạn cần nắm bắt các mục như sau :

  • Tìm đường đi ngắn nhất bằng Dijkstrabellman-Ford

  • Kiểm tra chu trình âm và ứng dụng của đường đi ngắn nhất

💡 THƯ VIỆN

Sử dụng các thư viện sau:

#include <stdio.h>    // thư viện cơ bản của C
#include <stdbool.h>  // hỗ trợ true/false cho C
#include "list.h"     // thư viện cá nhân hỗ trợ danh sách

⇣ Download thư viện list.hopen in new window

⚠️ LƯU Ý

Tất cả các đỉnh trong đồ thị bắt đầu từ 1 thay vì 0, nên hãy để ý rõ không thì sai !!!

Thuật toán Dijkstra

void dijksta(Graph G, int s, List *parrent, List *cost){
    bool mark[50];
    int u,v;
    for (u = 1; u <= G.n; u++){ //* khởi tạo mảng
        cost->Data[u] = 999;
        mark[u] = false;
        parrent->Data[u] = 0;
    }
    parrent->Size = cost->Size = G.n;

    cost->Data[s] = 0; //* đi từ đỉnh s, về đến đỉnh 
    parrent->Data[s] = -1; //* đỉnh bắt đầu không có parent 

    for (int i = 1; i <= G.n; i++){
        int min_pi = 999;
        for (int j = 1; j <= G.n; j++){
            //* Tìm đỉnh chưa duyệt có giá trị min_pi
            if(!mark[j] && cost->Data[j] < min_pi){
                min_pi = cost->Data[j];
                u = j;
            }
        }
        mark[u] = 1; //* đánh dấu đã duyệt xong đỉnh đó
        for (v = 1; v <= G.n; v++){
            if(G.A[u][v] != 0 && !mark[v]){
                int x = cost->Data[u] + G.A[u][v];
                if(x < cost->Data[v]){
                    cost->Data[v] = x;
                    parrent->Data[v] = u;
                }
            }
        }
    }
}

Thuật toán bellman-Ford

void bellmanFord(Graph G, int s,List *cost, List *parrent){
    for(int i=1; i<= G.n; i++){ // khởi tạo ban đầu
        cost->Data[i] = 999;
        parrent->Data[i] = 0;
    }

    cost->Size = parrent->Size = G.n;
    cost->Data[s] = 0; //có thể thay đổi
    parrent->Data[s] = -1; //có thể thay đổi

    for(int it = 1; it < G.n; it++){
        for(int k = 1; k <= G.m; k++){
            int u = G.edge[k].u;
            int v = G.edge[k].v;
            int w = G.edge[k].w;
            int x = cost->Data[u] + w;
            if(x < cost->Data[v]){
                cost->Data[v] = x;
                parrent->Data[v] = u;
            }
        }
    }
}

Mê cung số (nâng cao)

VÍ DỤ

💡 YÊU CẦU

  • Xuất phát từ góc trái bên trên của ma trận (cụ thể là 0)

  • Hãy tìm đường đi ngắn nhất từ vị trí xuất phát tới góc phải bên dưới của ma trận (cụ thể là 5)

==> Đường đi có chi phí thấp nhất cho ví dụ này là 24

int main(int argc, char const *argv[]){
    Graph G;
    makeNullGraph(&G);
    //freopen("dt.txt","r",stdin);
    int row,col;
    scanf("%d%d", &row,&col);
    G.n = row * col;
    init_Graph(&G, G.n);
    int M[MAX][MAX];
    for (int i = 0; i < row; i++){
        for (int j = 0; j < col; j++){
            scanf("%d",&M[i][j]);
        }
    }
    
    for (int i = 0; i < row; i++){
        for (int j = 0; j < col; j++){
            if(j + 1 == col){
                int x = i * col + j + 1;
                int y = (i+1) * col + j + 1;
                int t = M[i+1][j];
                add_edgeDirectionWeight(&G,x,y,t);
                G.m += 1;
            }
            else if(i + 1 == row){
                int x = i * col + j + 1;
                int y = i * col + (j+1) + 1;
                int t = M[i][j+1];
                add_edgeDirectionWeight(&G,x,y,t);
                G.m += 1;
            }
            else{
                int x = i * col + j + 1;
                int y1 = i * col + (j+1) + 1;
                int y2 = (i+1) * col + j + 1;
                int t1 = M[i][j+1];
                int t2 = M[i+1][j];
                add_edgeDirectionWeight(&G,x,y1,t1);
                add_edgeDirectionWeight(&G,x,y2,t2);
                G.m += 2;
            }            
        }
    }
    List cost; makeNullList(&cost);
    List parrent; makeNullList(&parrent);
    dijkstra(G,1,M[0][0],&parrent,&cost);
    
    printf("%d",cost.Data[G.n]);
    return 0;
}
Cập nhật lúc :
Tác giả: Zenfection, Zenfection