//本程序使用C++进行图的各种遍历运用型算法,基于贪心算法思想;
//参考书是人民邮电出版社的<<趣学算法>>;
//可移植性程序能在Linux/Mac os/Windows下运行;
//若有不足之处请提出,博主会尽所能修改;
//若是对您有用的话请点赞收藏或分享给它人;
//未经允许严禁抄袭以及转载;
//源代码奉上,希望能够对您有所启发;
//----------------------------------------------------------------------------------------------------;
//prim求最小生成树.cpp
/*
数据如下:
城市数量: 7
城市之间边的数量: 12
结点数u, v和权值w是:
1 2 23
1 6 28
1 7 36
2 3 20
2 7 1
3 4 15
3 7 4
4 5 3
4 7 9
5 6 17
5 7 16
6 7 25
输入其中一个城市结点: 1
最小花费应该分别是: 0 23 4 9 3 17 1
最小花费总和为: 57
*/
#include <iostream>
#include <climits>
using namespace std;
const int N = 100;
static bool flag[N]; //标记城市是否已经被访问过;
static int map[N][N]; //记录城市间的关系(邻接矩阵);
static int closest[N]; //记录城市之间的最近点;
static int lowcost[N]; //记录城市之间的最小开销;
void prim(int n, int u, int (*map)[N]);
int main(void)
{
int i, j, n, m, u, v, w, st, sumcost;
cout << "请您输入城市的个数: ";
cin >> n;
cout << "请您输入城市之间的边数: ";
cin >> m;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
map[i][j] = INT_MAX; //顶点之间都初始化为无关联;
}
}
cout << "请您输入城市之间的路线以及距离:\n";
for (i = 1; i <= m; i++)
{
cin >> u >> v >> w;
map[u][v] = map[v][u] = w; //无向图赋权值;
}
cout << "输入其中一个城市顶点: ";
cin >> st;
prim(n, st, map);
cout << "最小花费分别是:" << endl;
for (i = 1, sumcost = 0; i <= n; i++)
{
cout << lowcost[i] << ' ';
sumcost += lowcost[i]; //累增最小花费数额;
}
cout << "\n最小花费总和: " << sumcost << endl;
return 0;
}
void prim(int n, int u, int (*map)[N])
{
int i, j, t, temp;
flag[u] = true; //令u顶点加入至最小生成树中;
for (i = 1; i <= n; i++)
{
if (i != u)
{
lowcost[i] = map[u][i]; //初始化为u顶点到除u顶点外每个顶点的权值;
closest[i] = u; //初始化所有顶点的邻近关系都与u有关联;
flag[i] = false; //初始化除u之外的顶点不属于最小生成树中的集合;
}
else
{
lowcost[i] = 0; //自身的权值为0;
closest[i] = u; //自身的最近城市为自己;
}
}
for (i = 1; i <= n; i++)
{
temp = INT_MAX;
t = u;
for (j = 1; j <= n; j++)
{
if (!flag[j] && lowcost[j] < temp) //在V - U集合中寻找距离最小生成树集合最近的顶点t;
{
t = j;
temp = lowcost[j];
}
}
if (t == u)
{
break;
}
flag[t] = true;
for (j = 1; j <= n; j++)
{
if (!flag[j] && map[t][j] < lowcost[j]) //t到j的权值小于当前的邻近顶点的最小权值;
{
lowcost[j] = map[t][j]; //更新j的最邻近权值为t到j的边权值;
closest[j] = t; //更新j的最邻近点为t;
}
}
}
return;
}
//----------------------------------------------------------------------------------------------------;
//kruskal求最小生成树.cpp
/*
数据如下:
城市数量: 7
城市之间边的数量: 12
结点数u, v和权值w是:
1 2 23
1 6 28
1 7 36
2 3 20
2 7 1
3 4 15
3 7 4
4 5 3
4 7 9
5 6 17
5 7 16
6 7 25
城市结点从1开始进行计费;
最小花费总和为: 57
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100;
static int n, m; //城市的个数以及城市的边数;
static int nodeset[N]; //结点的集合号;
struct Edge
{
int u; //结点的行边;
int v; //结点的列边;
int w; //结点的权值;
} e[N * N];
bool comp(Edge x, Edge y); //比较边之间的权值:
void init(int n); //初始化每个城市的集合号;
int merge(int a, int b); //对每个城市的集合号进行处理;
int kruskal(int n); //kruskal算法构造最小生成树;
int main(void)
{
cout << "请您输入城市的个数: ";
cin >> n;
cout << "请您输入城市之间的边数: ";
cin >> m;
init(n);
cout << "请您输入城市之间的路线以及距离:\n";
for (int i = 0; i < m; i++)
{
cin >> e[i].u >> e[i].v >> e[i].w;
}
sort(e, e + m, comp); //依据边的权值来进行升序排序;
cout << "最小的花费是:" << kruskal(n) << endl;
return 0;
}
bool comp(Edge x, Edge y)
{
return x.w < y.w;
}
void init(int n)
{
for (int i = 1; i <= n; i++)
{
nodeset[i] = i; //初始化每一个城市的集合号;
}
return;
}
int merge(int a, int b)
{
int p = nodeset[a];
int q = nodeset[b];
if (p == q)
{
return 0;
}
for (int i = 1; i <= n; i++) //检查所有结点, 把集合号是q的改为p;
{
if (nodeset[i] == q)
{
nodeset[i] = p; //a的集合号赋值给b集合号;
}
}
return 1;
}
int kruskal(int n)
{
for (int i = 0, ans = 0; i < m; i++)
{
if (merge(e[i].u, e[i].v)) //2个结点不属于同一个集合;
{
ans += e[i].w; //累增一条边的权值;
if (--n == 1)
{
return ans;
}
}
}
return 0;
}
//----------------------------------------------------------------------------------------------------;
//dijkstra求单源最短路径.cpp
/*
数据如下:
城市个数: 5
城市之间路线个数: 11
城市之间路线以及距离:
1 5 12
5 1 8
1 2 16
2 1 29
5 2 32
2 4 13
4 2 27
1 3 15
3 1 21
3 4 7
4 3 19
您所在的位置可以输入是: 5
预计输出是:
5 -> 1 == 8
5 -> 2 == 24
5 -> 3 == 23
5 -> 4 == 30
5 -> 5 == 0
*/
#include <iostream>
#include <climits>
#include <stack>
using namespace std;
const int N = 100;
static bool flag[N]; //标记城市是否已经被访问过;
static int map[N][N]; //记录城市间的关系(邻接矩阵);
static int cities[N]; //记录城市的最短路径路线;
static int dist[N]; //记录城市间的最短距离;
void print_path(int u, int n); //打印源点u到各个关联顶点的最短路径路线;
void dijkstra(int u, int n, int m); //求单源最短路径算法;
int main(void)
{
int i, j, u, v, w, st, n, m;
//u和v是邻接矩阵的位置, w是权值;
//st是用户当前所在位置;
//n是城市的个数, m是城市间路线的条数;
cout << "请您输入城市的个数: ";
cin >> n;
cout << "请您输入城市之间的路线的个数: ";
cin >> m;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
map[i][j] = INT_MAX; //顶点之间都初始化为无关联;
}
}
cout << "请您输入城市之间的路线以及距离:\n";
while (m--)
{
cin >> u >> v >> w;
map[u][v] = min(map[u][v], w); //防止用户输入了2个顶点相同距离造成距离改变, 所以取的是最短的距离;
}
cout << "请输入您所在的当前位置: ";
cin >> st;
dijkstra(st, n, m);
cout << "您当前所在的位置是: " << st << endl;
print_path(st, n);
return 0;
}
void print_path(int u, int n)
{
int x;
stack<int> s;
for (int i = 1; i <= n; i++)
{
if (i == u)
{
continue;
}
x = cities[i];
while (x != -1)
{
s.push(x);
x = cities[x];
}
cout << "此位置到" << i << "顶点的最短路径是: ";
while (!s.empty())
{
cout << s.top() << " -> ";
s.pop();
}
cout << i << "\n最短距离是: " << dist[i] << endl;
}
return;
}
void dijkstra(int u, int n, int m)
{
int i, j, t, temp;
for (i = 1; i <= n; i++)
{
dist[i] = map[u][i]; //初始化源点u到其它各个顶点的最短路径长度;
flag[i] = false;
if (dist[i] == INT_MAX)
{
cities[i] = -1; //说明源点u到顶点i无边相连;
}
else
{
cities[i] = u; //说明源点u到顶点i有边相连;
}
}
flag[u] = true; //初始化集合中只有一个元素u被访问过;
dist[u] = 0; //初始化源点u到自己的最短路径为0;
for (i = 1; i <= n; i++)
{
temp = INT_MAX;
t = u;
for (j = 1; j <= n; j++) //在集合V - S中寻找距离源点u最近的顶点t;
{
if (!flag[j] && dist[j] < temp)
{
t = j; //记录距离源点u最近的顶点;
temp = dist[j]; //记录j顶点当前的距离;
}
}
if (t == u) //若找不到t则退出此函数, 无需再求最短路径;
{
return;
}
flag[t] = true; //否则则标记t为被访问的结点;
for (j = 1; j <= n; j++) //更新集合V - S中与t邻接的顶点到源点u的距离;
{
if (!flag[j] && map[t][j] != INT_MAX)
{
if (dist[j] > (dist[t] + map[t][j])) //经过t到达j的路径更短;
{
dist[j] = dist[t] + map[t][j];
cities[j] = t; //记录j顶点的前驱为t;
}
}
}
}
return;
}
//----------------------------------------------------------------------------------------------------;
//-------------------------------------------------2020年11月14日-------------------------------------------------------;