圖的最短路徑的問題

最近開始對圖進行了簡單的瞭解,只是寫了圖的單源最短路徑和最小生成樹的算法,不得不吐槽下,迪傑斯特拉和克魯斯卡爾這兩個名字都代表那個算法,讓我很暈總是記不住。
另外寫的時候可能會感覺到這個迪傑斯特拉算法和最小生成樹的prim算法有些相似,或者說是一樣的,其實並不是這樣 ,雖然二者都是貪心算法從最小的權值這個點入手,但是prim算法的最小權值是從全局出發的,也即是說整個圖中的最小權值的邊,而迪傑斯特拉則是針對某一個點來說的最小權值,即:是從這個點到其他點的最小權值的邊;

  1. 列表內容
//圖的單元最短路徑的地傑斯特拉算法,時間複雜度爲O(n^2)
//適用於求邊的權值爲正數的圖
#include<iostream>
#include<vector>
#include<cstdlib>
#include<stack>
using namespace std;


template <typename T>
class grapth
{
public:
    const int maxvalue;
    grapth(int n = 5):maxvalue(6666)
    {
        edge.resize(n);
        path.resize(n);
        for (int i = 0; i < n; i++)
        {
            edge[i].resize(n);
            path[i] = 0;
        }
        path[0] = -1;
        set_data(n);
        set_dist(n);
    }
    void min_path();
    void min_path(T n);
    void show();
    void set_data(int);
    void set_dist(int);
    typedef  T  value_type;
private:
    int min()
    {
        int min = maxvalue;
        int ret = 0;
        for (int i =0;i < dist.size();++i)
        {
            if (dist[i] >0 && dist[i] < min)
            {
                min = dist[i];
                ret = i;        
            }
        }
        return ret;
    }
    int min(int i)
    {
        T  min  = 65535;
        T  node = 0;
        for (auto it = dist.begin(); it != dist.end(); ++it)
        {
            if (*it != -1 && *it < min)
            {
                min = *it;
                node = it - dist.begin();
            }
        }
        return node;
    }
    struct resu
    {
        int tail;
        int head;
    };
    void update(int );
    vector<vector<T>> edge;//用來存放邊的權值
    vector<T> dist;//輔助空間,用來存放當前的各個頂點最短路徑。
    vector<T> s;//已經加入到的求出頂點集。
    vector<T> path;//用來存放最終的求出的路徑,存放父親。
    T v;

};


/*更新dist數組的策略
*如果該節點沒有加到s中去。且這個節點到新加入s節點中的路徑長度小於當前的
那麼就更新。
*/
template<typename T>
void grapth<T>::update(int curr)
{
    for (int i = 0; i < dist.size(); ++i)
    {
        int min = (dist[curr] + edge[i][curr]);
        if (dist[i] != -1 && dist[i] > min)
        {
            dist[i] = min;
            path[i] = curr;
        }
    }   
}

template <typename T>
void grapth<T>::set_data(int n)
{
    int lef = 0;
    int rig = 0;
    int weig = 0;
    int k = 0;
    cout << "num of shizi:";
    cin >> k;
    for (int i = 0; i < k; ++i)
    {
        cin >> lef >> rig >> weig;
        edge[rig][lef]  = edge[lef][rig] = weig;
    }
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < n; ++j)
        {
            if (edge[i][j] > 0)
            {
                continue;
            }
            edge[i][j] = maxvalue;
        }
        edge[i][i] = 0;
    }

}

template<typename T>
void grapth<T>::set_dist(int n)
{
    int v;
    cout << "v:\n";
    cin >> v;
    s.push_back(v);
    this->v = v;
    for (int i = 0; i < n; ++i)
    {
        dist.push_back(edge[v][i]);
    }
    dist[v] = -1;
}


/*
求單元最短路徑
首先從dist數組中選出s集合中的頂點到各個節點的最小路徑的節點
加入到s集合中去,更新dist數組。把對應節點刪除掉。
然後繼續找直到所有節點都找完
*/
template <typename T>
void grapth<T>::min_path()
{
    static int count = 1;
    if (count == dist.size())
        return;
    int i = min();
    s.push_back(i);
    update(i);
    dist[i] = -1;
    count++;
    min_path();
}
template <typename T>
void grapth<T>::min_path(T n)
{
    for (int i = 0; i < dist.size(); ++i)
    {
        int v = min(i);
        s.push_back(v);
        update(v);
        dist[v] = -1;
    }
}
template<typename T>
void grapth<T>::show()
{
    stack<T> minp;
    for (int i = 0; i < dist.size(); ++i)
    {
        minp.push(i);
        if (i == v)
            continue;
        int tail = i;
        int j = 0;
        for (; j < dist.size(); ++j)
        {
            if (j == tail)
            {
                minp.push(path[j]);
                tail = path[j];
                j = 0;
            }
        }
        while (!minp.empty())
        {
            cout <<minp.top()<<"->";
            minp.pop();
        }
        cout << endl;
    }
}
int main()
{
    /*
    輸入:
    7
    0 1 10
    0 3 30
    0 4 100
    1 2 50
    2 4 10
    3 2 20
    3 4 60
    0
    */
        grapth<int> mg(5);
        mg.min_path(1);
        mg.show();
        return 0;

}
#include<iostream>
#include<cstdlib>
using namespace std;


/*
該算法可以用來求權值爲負數的圖的單源最短路徑
但是不能夠是由帶負權值的邊組成的迴路的圖。
*/
#define SIZE 7

int edge[7][7];
int dist[7];
int path[7];
int v = 0;
void init()
{
    for (int k = 0;k < SIZE;++k)
    {
        for (int h = 0; h < SIZE; ++h)
            edge[k][h] = 6554;
    }
    int lef, rig, data;
    while (cin >> lef, lef >= 0)
    {
        cin >> rig >> data;
        edge[lef][rig] = data;
    }
    for (int i = 0; i < SIZE; ++i)
    {
        dist[i] = edge[v][i];
        if (i == v)
            path[i] = -1;
        else
            path[i] = v;
    }
}
/*
用了一個數組用來存放最小的邊。
dist,從k = 2 開始求,意思是經過2條邊到達終點的最小邊。比較通過k-1條邊+這條邊到終點的值
和k-1條邊到終點那個路徑最小。則dist存放哪個。
*/
void bellman_ford()
{
    for (int i = 2; i < SIZE;++i)////kkkkkk
    {
        for (int j = 0; j < SIZE; ++j)
        {
            if (j == v)continue;
            for(int u = 0;u < SIZE;++u)
            {
                if (u != j && dist[j] > dist[u] + edge[u][j])
                {
                    dist[j] = dist[u] + edge[u][j];
                    path[j] = u;
                }
            }
        }
    }
}
void show()
{
    for (int i = 0; i < SIZE; ++i)
    {

            cout << dist[i]<<"  ";
    }
    cout << endl;
    for (int i = 0; i < SIZE; ++i)
    {

        cout << path[i] << "  ";
    }
}
int main()
{
    /*輸入:
0 0 0
0 1 6
0 2 5
0 3 5
1 1 0
1 4 -1
2 1 -2
2 4 1
3 2 -2
3 3 0
3 5 -1
4 4 0
4 6 3
5 5 0
5 6 3
6 6 0
-1*/
    init();
    bellman_ford();
    show();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章