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