当前主要版本
第一代· 无向矩阵型(鸿蒙·乾坤Day67)(DEV-CPP)测试版本
部分高级功能缺失,是探索性模板,由于宏观设计不合理,已经停止维护
第二代·综合矩阵型(鸿蒙·乾坤Day107)(VSCode)集成版本
可切换【有向/无向】,更优化的功能
当前问题:矩阵太小,大了程序会崩;存在部分bug
正在研究:SPFA等拓展
VSC对switch的缩进怎么这么恶心
第三代·邻接表·动态内存型(寒假开发)旗舰版本(已经咕咕)
主要功能·二代
一、基础编辑
1.创建·清空 全图
2.点:新建·删除·修改(名称)·探测(邻接情况)【a到a bug】
3.边:新建·删除·修改(权值)【负权值 bug】
4.切换:有向图/无向图
5.更迭:启动点(用于启发BFS/DFS)
二、辅助功能
1.Find:输入【点·名称】,返回在点表中的【位置】
2.Same:【点·名称】查重(寒假开发)
3.判断【孤立点】【存在回环】?(寒假开发)
三、进阶功能
1.最小生成树(无向图时启动):Prim/Kruskal(寒假·后者有bug·需要并查集知识)
2.广搜/深搜:BDS/DFS(寒假)有向图更迭启动点后出现bug
3.最短路径:Dijkstra/Floyd【显示路径】
储备功能·三代旗舰
1.删除点(动态内存维护malloc free)
2.对vector容器、STL库queue stack等应用
3.SPFA、拓扑排序、关键路径
4.更好的视图
测试截图
感谢网上大佬帮我搭建的VSC环境!C++和Python~之前好像有发现网友开发的
一键搭建VSC C++环境工具包,我寒假一定要给他找回来(工具包被我删了)
T2型-矩阵·综合(先进版本,正在开发)
#include <iostream>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <malloc.h>
#include <string.h>
#include <vector>
//#include <bits/stdc++.h>
#define maxx 0x3f3f3f3f
#define minn (1 << 31)
#define max 100 //过大会导致函数崩溃,可能是内存过载导致
using namespace std;
//基本数据部署
bool v[max];
bool Direction = true; //默认为有向图
int dis[max], from[max];
bool use[max];
int A[max][max], cost; //存当前的最短路径长度
int Path_Floyd[max][max]; //存递归需要的回溯路径
//结构体数据部署
typedef struct G //【综合·有向图·矩阵】
{
char name[max][27]; //顶点名称
int map[max][max]; //边·矩阵
int edge, node, start;
};
typedef struct T //【Prim算法·辅助】
{
int minDis, parent;
};
typedef struct kus
{ //克鲁斯卡尔辅助数组
int begin, end;
int weight;
};
vector<kus> KU; //【科研突破!矢量容器】
G a;
//辅助功能
bool pd1(kus a, kus b) // sort判断【边权值,从小到大】小的往前走
{
return a.weight < b.weight;
}
bool init(G &a) //初始化
{
a.edge = 0;
a.node = 0;
memset(a.name, 0, sizeof(a.name));
int x, y, z;
for (x = 0; x < max; x++)
for (y = 0; y < max; y++)
a.map[x][y] = maxx;
a.start = 0;
return true;
}
bool find(G a, char t[], int &e) //结点位置追踪
{
int x, y, z;
for (x = 0; x < a.node; x++)
{ //对x位置进行检查
z = 1;
for (y = 0; y < strlen(a.name[x]); y++) //对各个字母进行检查
{
if (t[y] != a.name[x][y])
{
z = 0;
break;
}
}
if (z == 1)
{
e = x;
return true;
}
}
printf("结点名称异常!(%s)请重新输入\n", t);
e = -1;
return false;
}
bool same(G a, char t[]) //结点名称查重
{ //寒假处置
return false;
}
void path(G a, int now) //迪杰斯特拉算法路径1
{
if (from[now] == -1)
return;
path(a, from[now]);
printf("%s->", a.name[from[now]]);
}
void init_Floyd(int z, G a)
{
int x, y;
for (x = 0; x < z; x++)
for (y = 0; y < z; y++)
{
A[x][y] = a.map[x][y];
Path_Floyd[x][y] = -1;
}
}
void find_path_Floyd(int x, int y, G a)
{
// printf("追踪!\n");
if (Path_Floyd[x][y] == -1)
{
printf("(%s-->%s) ", a.name[x], a.name[y]);
cost += a.map[x][y];
}
else
{
int mid = Path_Floyd[x][y];
find_path_Floyd(x, mid, a);
find_path_Floyd(mid, y, a);
}
}
//地图编辑
bool crate(G &a) //创建图
{
int x, y, z, z1, z2;
char t1[27], t2[27];
printf("1.宏观部署!\n n个点m条边:");
scanf("%d%d", &a.node, &a.edge);
printf("2.基础部署·点!\n");
for (x = 0; x < a.node; x++)
{
printf(" 输入第%d点名称:", x + 1);
scanf("%s", &t1);
if (same(a, t1))
x--;
else
strcpy(a.name[x], t1);
}
printf("3.基础部署·边!\n");
for (x = 1; x <= a.edge; x++)
{
z1 = z2 = 0;
memset(t1, 0, sizeof(t1));
memset(t2, 0, sizeof(t2));
printf(" %3d:输入【两点名称】+【权值】:", x);
scanf("%s%s%d", &t1, &t2, &y);
if (!find(a, t1, z1) || !find(a, t2, z2))
{
x--;
continue;
}
if (a.map[z1][z2] != maxx)
printf("覆盖为");
printf(" map[%d][%d]=%d\n", z1, z2, y);
if (Direction)
a.map[z1][z2] = y;
else //无向图
{
kus b; //为克鲁斯卡尔算法部署边
b.begin = z1;
b.end = z2;
b.weight = y;
KU.push_back(b); //塞进容器
a.map[z1][z2] = y; //矩阵部署边
a.map[z2][z1] = y;
}
}
printf("4.最终部署·启动点!\n");
do
{
scanf("%s", &t1);
} while (!find(a, t1, z));
printf("部署成功! %s - a.name[%d]\n", a.name[z], z);
a.start = z;
return true;
}
bool change_node(G &a)
{
int x, y, z;
char t[27];
printf("输入您想修改的结点名称:");
do
{
scanf("%s", &t);
} while (!find(a, t, z));
printf("输入新节点名称:");
scanf("%s", &t);
memset(a.name[z], 0, sizeof(a.name[z]));
strcpy(a.name[z], t);
return true;
}
bool change_edge(G &a)
{
int x, y, z1, z2;
char t1[27], t2[27];
printf("输入两个结点以确定一条边:\n");
printf(" 起点名称:");
do
{
scanf("%s", &t1);
} while (!find(a, t1, z1));
printf(" 终点名称:");
do
{
scanf("%s", &t2);
} while (!find(a, t2, z2));
printf(" 部署权值(输入0为删除):");
scanf("%d", &x);
if (x == 0)
x = maxx;
printf("map[%d][%d]=%d\n", z1, z2, x);
if (Direction)
a.map[z1][z2] = x;
else
{
a.map[z1][z2] = x;
a.map[z2][z1] = x;
}
return true;
}
bool add_node(G &a)
{
if (max == a.node)
{
printf("已饱和!添加失败。");
return false;
}
printf("输入新节点名称:");
scanf("%s", &a.name[a.node]);
printf("第%d个结点[%s],已部署至a.name[%d]!\n", a.node + 1, a.name[a.node], a.node);
a.node++;
return true;
}
void search(G a)
{
printf("输入您想探测的点名称:");
int x, y, z;
char t[27];
scanf("%s", &t);
if (find(a, t, z))
{
printf("此点【起点】,可以【前往】的地点:\n");
y = 0;
for (x = 0; x < a.node; x++)
if (a.map[z][x] != maxx)
printf("%d:%s\n", ++y, a.name[x]);
printf("\n");
printf("此点为【终点】,可以由以下点【抵达】:\n");
y = 0;
for (x = 0; x < a.node; x++)
if (a.map[x][z] != maxx)
printf("%d:%s\n", ++y, a.name[x]);
printf("\n");
}
}
//高级功能
bool dfs2(G a, int w)
{
printf("%3s ", a.name[w]);
v[w] = true;
for (int x = 0; x < a.node; x++)
if (a.map[w][x] != maxx && !v[x])
dfs2(a, x);
return true;
}
bool DFS(G a)
{
int x, y, z;
for (x = 0; x < a.node; x++)
v[x] = false; //初始化标记未访问过
// printf("%d",a.node);
for (x = 0; x < a.node; x++)
{
if (!v[x])
dfs2(a, a.start);
}
return true;
}
bool BFS(G a, int w)
{
queue<int> Q;
int x, y, z;
for (x = 0; x < a.node; x++)
v[x] = false;
printf("%3s ", a.name[w]);
v[w] = true;
Q.push(w); //当前点入队,准备对下属层的点进行遍历
while (!Q.empty())
{ //遍历完成才会跳出,全跳出技术
y = Q.front();
Q.pop(); //出队赋值,开始遍历
for (x = 0; x < a.node; x++) //以Y为依托,遍历进攻
{
if (a.map[y][x] != maxx && !v[x])
{
printf("%3s ", a.name[x]);
v[x] = true;
Q.push(x); //入队,等会从这里开始打印
}
}
}
return true;
}
bool Prim(G a) //树集合,邻接边选小入,扩增点
{
bool n[max]; //标记·是否处于【最小生成树中】
T we[max];
//辅助·【minDis】·与【生成树】邻接的最小边 【parent】·这个点最小值的【更迭】来自于谁【两点确定一条线】
int sum = 0, x, y, k, min;
// xy临时数据,sum是对边权值进行累加,min负责筛选更新后点
for (x = 0; x < a.node; x++)
{
n[x] = false;
we[x].parent = a.start;
we[x].minDis = a.map[a.start][x];
}
n[a.start] = true;
for (x = 1; x < a.node; x++)
{
min = maxx;
for (y = 0; y < a.node; y++) //【物色·下一个加入点】
{
if (n[y] == false && we[y].minDis < min) //【没被选过+数值更小】
{ //如果【此点可选】,且【记录min】更小
min = we[y].minDis;
k = y; //更新min所处位置
} //更新min的值 为了筛选 下一个【加入树の点】
}
printf("<%s,%s> ", a.name[k], a.name[we[k].parent]);
sum += we[k].minDis;
n[k] = true;
for (y = 0; y < a.node; y++)
{
if (n[y] == false && a.map[k][y] < we[y].minDis)
{
we[y].parent = k;
we[y].minDis = a.map[k][y];
}
}
// minDis表维护完成
}
printf("All_Cost=%d\n", sum);
return true;
}
bool Kruskal(G a) //边排序,选小入,去回环
{ //有bug,技术能力不够,暂时不修复,寒假处置
sort(KU.begin(), KU.end(), pd1);
int loop[max], sum = 0, n = 0; //统计边的权值·个数
int x, y, z1, z2;
for (x = 0; x < a.node; x++)
loop[x] = x;
for (x = 0; x < a.node; x++)
{
if (n + 1 == a.node)
break;
z1 = loop[KU[x].begin];
z2 = loop[KU[x].end];
if (z1 != z2)
{
printf("<%s,%s> ", a.name[KU[x].begin], a.name[KU[x].end]);
sum += KU[x].weight;
for (y = 0; x < a.node; y++)
{
if (loop[y] == z2)
loop[y] = z1;
}
n++;
}
}
printf("All_Cost=%d\n", sum);
//可能要用到并查集,现阶段技术不够
return true;
}
bool Dijkstra(G a)
{
int n = a.node, min;
int k, x, y, z, now = a.start;
for (x = 0; x < n; x++)
{
use[x] = false;
dis[x] = a.map[now][x];
if (dis[x] != maxx)
from[x] = now;
else
from[x] = -1;
}
use[now] = true;
dis[now] = 0;
//初始化结束
for (x = 1; x < n; x++) //战略指挥!执行n-1次
{
min = maxx;
for (y = 0; y < n; y++) //寻找最小点k
if (!use[y] && dis[y] < min) //没用过且dis更小
{
k = y;
min = dis[y];
}
use[k] = true; //标记k,作为下一次攻击启动点
//更新从源点触发到其他个点的最短路径
for (y = 0; y < n; y++)
{
if (!use[y] && dis[k] + a.map[k][y] < dis[y])
//【bug修复】:maxx+6就变成负数了,会判定为最小值
{ //因为int (1<<31)-1再加就变成负数溢出
//而0x3f3f3f3f差不多是max的一半,常规输入不会溢出
dis[y] = dis[k] + a.map[k][y];
printf("k=%d y=%d dis[y]=%d\n", k, y, dis[y]);
from[y] = k; //标记攻击来源点
}
}
}
//打印模块
printf("目标点\t最短路径值\t最短路径\n");
for (x = 0; x < a.node; x++)
{
if (x != now)
{
printf(" %s\t %d\t", a.name[x], dis[x]);
path(a, x);
printf("%s\n", a.name[x]);
}
}
return true;
}
bool Floyd(G a)
{
init_Floyd(a.node, a); //初始化!path部署-1,map部署给A
int x, y, z;
for (z = 0; z < a.node; z++) //选【中间点】,尝试插入
{
for (x = 0; x < a.node; x++)
{
for (y = 0; y < a.node; y++)
{
if (x == y || z == x || z == y)
continue;
if (A[x][y] > A[x][z] + A[z][y])
{
A[x][y] = A[x][z] + A[z][y];
Path_Floyd[x][y] = z;
}
}
// cout << endl;
}
// printf("\n\n");
}
/*
关于path=-1的意义:说明有直接的边相连
*/
return true;
}
//视觉模块
bool map(G a)
{
int x, y;
printf(" ");
for (x = 0; x < a.node; x++)
printf(" %3s", a.name[x]);
printf("\n");
for (x = 0; x < a.node; x++)
{
printf(" %3s", a.name[x]);
for (y = 0; y < a.node; y++)
{
if (a.map[x][y] == maxx)
printf(" 0");
else
printf(" %3d", a.map[x][y]);
}
printf("\n");
}
return true;
}
bool menu(G a, int &x) //菜单
{
system("cls");
if (a.node != 0)
{
printf("图·矩阵汇报\n");
map(a);
printf("\n");
printf("DFS:");
DFS(a);
printf("\n");
printf("BFS:");
BFS(a, a.start);
printf("\n");
if (!Direction)
{
printf("最小生成树·Prim:");
Prim(a);
printf("\n");
printf("最小生成树·Kruskal:");
// Kruskal(a);
printf("\n");
}
}
// DFS
// BFS
//最小生成树 Prim算法(依边选点)
//最小生成树 Kruskal算法(依点选边)·不产生回路
if (Direction)
printf("\n\n《有向图·矩阵·综合实现》 鸿蒙纪元·乾坤Day107\n");
else
printf("\n\n《无向图·矩阵·综合实现》 鸿蒙纪元·乾坤Day107\n");
printf("1-创建图 2-修改·添加·删除边 3-修改点名称\n");
printf("4-最短路径Dijkstra 5-最短路径Floyd \n");
printf("6-初始化 7-添加新点\n");
printf("2745-退出 5257-有/无 向图切换 \n");
printf("2333-启动点更迭 8-点·信息探测\n");
//删除模块对矩阵不友好,时间有限,实践算法有限,决定抛弃
printf("输入您的选择:");
scanf("%d", &x);
if (x == 2745)
return false;
if (x == 5257)
Direction = !Direction;
return true;
}
/*测试数据T1(顺推探测·测试最短路径)
1 8 11
a b c d e f g h
a h 1 a b 2 b c 3 c d 4
h f 5 b f 6 b e 7 e c 8
d g 9 f g 10 h d 11
a
*/
/*测试数据T2(树型结构·测试遍历D/BFS)
1 19 18
a b c d e f g h i j k l m n o p q r s
a b 1 a c 1 a d 1 d e 1 c q 1 d m 1
d n 1 d o 1 d p 1 q r 1 r s 1 e l 1
e f 1 f k 1 f g 1 g h 1 h i 1 g j 1
a
*/
/*测试数据T3(无向图·测试生成树)
5257
1 8 11
a b c d e f g h
a h 1 a b 2 b c 3 c d 4
h f 5 b f 6 b e 7 e c 8
d g 9 f g 10 h d 11
a
*/
/*测试数据T4(佛洛依德异常情况测试)
1 4 8
0 1 2 3
0 1 5 2 0 3 0 3 7 1 3 1
1 2 4 2 1 3 2 3 2 3 2 1
0
*/
int main()
{
int x, y, z;
init(a);
char t[27], tt[27];
while (menu(a, x))
{
switch (x)
{
case 1:
{
crate(a);
break;
}
case 2:
{
change_edge(a);
break;
}
case 3:
{
change_node(a);
break;
}
case 4:
{
Dijkstra(a);
break;
}
case 5:
{
Floyd(a);
printf("Path情况汇报:\n");
for (int s1 = 0; s1 < a.node; s1++)
{
for (int s2 = 0; s2 < a.node; s2++)
{
printf("%3d ", Path_Floyd[s1][s2]);
}
cout << endl;
}
cout << endl;
printf("Floyd计算完成!\n");
do
{
printf("输入需要查询【最短路径】の两点名称:");
scanf("%s%s", &t, &tt);
} while (!find(a, t, y) || !find(a, tt, z));
printf("<%s,%d> ===> <%s,%d>追踪启动!\n", a.name[y], y, a.name[z], z);
cost = 0;
find_path_Floyd(y, z, a);
printf("总长度:%d\n", cost);
break;
}
case 6:
{
init(a);
break;
}
case 7:
{
add_node(a);
break;
}
case 8:
{
search(a);
break;
}
case 5257:
{
printf("更迭进化!");
break;
}
case 2333:
{
printf("启动点更迭!输入新启动点名称:");
do
{
scanf("%s", &t);
} while (!find(a, t, z));
printf("部署成功! %s - a.name[%d]\n", a.name[z], z);
a.start = z;
break;
}
default:
printf("输入异常!");
}
system("pause");
}
system("pause");
return 0;
}
T1型-无向矩阵(已停止维护)
测试数据 T2基础图形
(孤立点:德玛西亚 启动点:a)
1 9 11 a b c d e f g h 德玛西亚 a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11 a
测试数据 T3·三叉树
(无·孤立点 启动点:a)(图没了懒得画)
1 12 11 a b c d e f g h i j k L a b 1 a c 1 a d 1 b e 1 b f 1 f g 1 f h 1 d i 1 i j 1 i k 1 i L 1 a
#include <iostream>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <algorithm>
#define max 2745
#define maxx (1 << 31) - 1
using namespace std; //以0为INFINITY,不知道为什么memset对infinity会赋值为-1
typedef struct G
{ // Graph
char node[max][27]; //点·符号
int n, e; //点、边·个数
};
typedef struct FZ
{ // Prim算法所用数据结构
int x; //最小边在集合U(最小边在当前子树顶点集合中的那个顶点的下标)
int min; //最小边上的权值
};
int map[max][max] = {}, nmax = 0, star = 0, alone = 0; //矩阵·权值记录;启动点·用于启动DFS和 拓扑排序;存在几个孤立点
int n[max][max]; //《佛洛依德·路径矩阵》
bool v[max], LT; // DFS访问标志
//综合图·三叉树·连通图
// 1 9 11 a b c d e f g h 德玛西亚 a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11 a
// 1 12 11 a b c d e f g h i j k L a b 1 a c 1 a d 1 b e 1 b f 1 f g 1 f h 1 d i 1 i j 1 i k 1 i L 1 a
// 1 8 11 a b c d e f g h a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11 a
//【正在开发!鸿蒙纪元·乾坤Day62--Day】
//《佛洛依德路径·Kruskal》
//《判断辅助·功能区》
bool pd1(int t1, int t2, int t)
{ //《佛洛依德·矩阵更迭判断》
if ((t1 != 0 && t2 != 0) && ((t1 + t2 < t && t != 0) || (t == 0)))
return true;
else
return false;
}
bool pd2(G a, int x)
{ //《判断·是否删除点》
if (a.node[x][0] == '\0')
return true;
else
return false;
}
bool loop(G a)
{ //《判断·存在回路?》
return true;
}
bool empty(G a)
{ //《判断·空图》
if (a.n == 0 && a.e == 0)
return true;
else
return false;
}
bool find(G a, char t[], int &x)
{ //《寻找·依结点名称·返回char中的存储位置》
int y, z, s = 0; // 0没找到
for (y = 1; y <= a.n; y++)
{
s = 1; //默认找到
for (z = 0; z <= strlen(a.node[y]); z++)
if (a.node[y][z] != t[z])
{ //出现不同
s = 0; //标记不同
break;
}
if (s == 1)
{ //发现位置!
x = y;
return true;
}
}
printf("结点名称异常!(%s)请重新输入\n", t);
return false;
}
bool wrong(char a[])
{ //《异常输入阻断》
char b[20] = "Teloy_SXH";
for (int x = 0; x < strlen(a); x++)
if (b[x] != a[x])
return false;
return true;
}
//《强化算法·功能区》
bool dfs(G a, int w)
{ //《DFS·递归执行》
if (!v[w])
printf("%s ", a.node[w]);
v[w] = true;
for (int x = 1; x <= nmax; x++)
if (map[w][x] != 0 && !v[x] && !pd2(a, x)) //有通路且没走过且空
dfs(a, x);
return true;
}
bool DFS(G a, int w)
{ //《DFS·指挥模块》
for (int x = 1; x <= nmax; x++)
v[x] = false; //初始化,都没访问过
for (int x = 1; x <= nmax; x++)
if (!v[x] && a.node[x][0] != '\0') //没访问过,且不是空点
dfs(a, w);
return true;
}
void BFS(G a, int w)
{ //《BFS·直接执行》
queue<int> Q; //对启动点单独处理
int n = 1;
for (int x = 1; x <= nmax; x++)
v[x] = false; //初始化,都没访问过
printf("%s ", a.node[w]); //打印
v[w] = true; //标记访问
Q.push(w); //入队!
while (!Q.empty())
{
int y = Q.front();
Q.pop(); //出队,赋值于y
for (int x = 1; x <= nmax; x++)
{ //遍历x是y下层所有点
if (map[y][x] != 0 && !v[x] && !pd2(a, x))
{
printf("%s ", a.node[x]);
v[x] = true;
n++;
Q.push(x);
}
} // 1 12 11 a b c d e f g h i j k L a b 1 a c 1 a d 1 b e 1 b f 1 f g 1 f h 1 d i 1 i j 1 i k 1 i L 1 a
}
if (n == a.n) //连通图
LT = true;
else
LT = false;
}
bool Dijkstra(G a, int w1, int w2)
{ //《迪杰斯特拉·最短路径》· eloge
printf("矩阵流,无法使用<迪杰斯特拉>最短路径探测算法!\n");
return false;
}
bool Floyd(G a, int w1, int w2)
{ //《佛洛依德·最短路径》·n^3·
printf("最短路径探测!<佛洛依德>算法(Floyd)\n"); //意识:从w1到w2
int m[nmax + 1][nmax + 1], x, y, z, t1, t2, t3;
for (x = 1; x <= nmax; x++)
for (y = 1; y <= nmax; y++)
{
m[x][y] = map[x][y];
//迭代图·复制·初始化
}
//《初始化·完成》
//《算法启动》
for (x = 1; x <= nmax; x++)
{ //遍历n次·插入点
if (pd2(a, x))
continue;
for (y = 1; y <= nmax; y++)
{ //出发点
if (pd2(a, y) || y == x)
continue;
for (z = 1; z <= nmax; z++)
{ //终点
if (pd2(a, z) || z == x || z == y)
continue;
//思想,从y到z,插入x是否可行(条件保障·点存在·三点不重复)
if (pd1(m[y][x], m[x][z], m[y][z])) //没路但是可以连接,或者,有更短路且直连不是0
m[y][z] = m[y][x] + m[x][z]; //插入x作为中转
}
}
}
//《算法·结束》
if (m[w1][w2] == 0)
{
printf("两点间不存在路径!\n");
return false;
}
else
{
printf("最短路径长度:%d\n路径追踪:", m[w1][w2]);
printf("\n\n");
return true;
}
}
bool Prim(G a)
{ //《普利姆·最小生成树》
FZ T[max];
int x, y, z;
int i, j, k; //辅助数组T 上边存的是他老爹是谁,下面一个存的是最小边的权值
int go = star - 1, sum = 0, min;
int gg[a.n][a.n] = {};
for (x = 0; x < a.n; x++)
{ //《生成·新体系》·对角线全=0·0区改maxx
for (y = 0; y < a.n; y++)
if (map[x + 1][y + 1] == 0 && x != y)
gg[x][y] = maxx;
else
gg[x][y] = map[x + 1][y + 1];
}
//《初始化·完成》
//《算法·启动》
for (x = 0; x < nmax; x++)
{ //《初步·启动点加入生成树》
T[x].x = go;
T[x].min = gg[go][x];
}
for (x = 1; x < nmax; x++)
{ //《探索!剩余n-1个点!》
if (pd2(a, x + 1))
continue;
min = maxx;
for (y = 0; y < nmax; y++)
{ //【寻找·辐射点·权值最小边】辐射点·与已生成的树直接连接的点
if (pd2(a, y + 1))
continue;
if (T[y].min != 0 && T[y].min < min)
{ //可选且权值更小(进入生成树的点会标注0!!)
min = T[y].min;
k = y; //记录 权值 地址
}
}
printf("<%s,%s>", a.node[k + 1], a.node[T[k].x + 1]); //进入·打印
sum += T[k].min;
z++;
for (y = 0; y < nmax; y++)
{ //《加入·更迭辅助区》
if (pd2(a, y))
continue;
if (T[y].min != 0 && gg[k][y] < T[y].min)
{ //目标点不在树内 且 (由新加入点到目标点)地图路径更短
T[y].x = k; //更迭辅助区
T[y].min = gg[k][y];
}
} //叠加!边的权值
}
printf("总权值:%d\n", sum);
}
bool Kruskal(G a)
{ //《克鲁斯卡尔·最小生成树》·eloge
printf("\n");
} //自适应选择,对比算法复杂度
bool top_sort(G a, int w)
{ //《拓扑排序》 (有向图)
printf("无向图不实现!");
return true;
}
//《基础控制·功能区》
bool init(G &a)
{ //《图·初始化》
a.n = 0;
a.e = 0;
nmax = 0;
star = 0; //最大矩阵长度,防止删点导致矩阵打印异常
memset(a.node, '\0', sizeof(a.node));
memset(map, 0, sizeof(map)); //初始化0,默认不存在路径
return true;
}
bool mapp(G a)
{ //《打印·矩阵·结点对应情况》
int x, y;
printf("\n边·矩阵情况\n");
for (x = 1; x <= nmax; x++)
{
for (y = 1; y <= nmax; y++)
printf("%-3d ", map[x][y]);
printf("\n");
}
printf("\n点·node情况\n");
for (x = 1; x <= nmax; x++)
{
printf("%d\t", x);
if (a.node[x][0] == '\0')
printf("被删除的点(空位)\n");
else
printf("%s\n", a.node[x]);
}
}
bool go_star(G a)
{ //《部署·启动点》
int x;
char t[20];
do
{
printf("输入启动点:");
memset(t, '\0', sizeof(t));
scanf("%s", &t);
} while (!find(a, t, x));
star = x;
printf("部署启动点<%s>于node[%d]!", a.node[x], x);
return true;
}
bool create(G &a)
{ //《创建·全图》 清空后重建会出现构建bug
if (!empty(a))
return false;
printf("几个点?几条边?");
scanf("%d%d", &a.n, &a.e);
if (a.e > a.n * (a.n - 1) / 2)
{
init(a);
printf("无向图·边数溢出!\n");
return false;
}
if (a.n < 1)
{
init(a);
printf("无向图·结点非法!\n");
return false;
}
int x, y, z, s;
printf("输入结点名称:\n");
for (x = 1; x <= a.n; x++)
{
printf("%d号结点:", x); //注释化!读入情况查看
scanf("%s", a.node[x]);
}
/*printf("\n读入完成,汇报情况如下:\n"); //4 4 a b c d a b 1 a c 2 a d 3 b c 4
for(x=1;x<=a.n;x++)
printf("%d\t%s\n",x,a.node[x]);*/
printf("\n\n");
char t1[20] = {}, t2[20] = {};
printf("部署无向边(俩结点名称·空格隔开+边权)\n");
for (x = 1; x <= a.e; x++)
{
do
{
memset(t1, '\0', sizeof(t1));
memset(t2, '\0', sizeof(t2));
scanf("%s%s%d", &t1, &t2, &s);
} while (!find(a, t1, y) || !find(a, t2, z) || map[y][z] != 0 || s == 0);
//结点名称异常导致没找到,或者已经存在边!=1,或者边=0
printf(" %s位于%d %s位于%d 建立无向边权值=%d\n", t1, y, t2, z, s);
map[y][z] = s;
map[z][y] = s; //地图权值赋予
}
go_star(a);
return true;
}
bool del1(G &a)
{ //《删除·点》
printf("输入结点名称:");
int x, y, z;
char t1[20] = {};
do
{
memset(t1, '\0', sizeof(t1));
scanf("%s", &t1);
if (wrong(t1))
return false;
} while (!find(a, t1, z));
// 1 9 11 a b c d e f g h 德玛西亚 a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11 a
//结点名称异常导致没找到
printf("%s位于%d,单点移除!\n", t1, z);
memset(a.node[z], '\0', sizeof(a.node[z])); //全部置零
for (x = 1; x <= a.n; x++)
{
if (map[x][z] != 0 && map[z][x] != 0)
{ //行列全部置空,表示移除所有边
map[x][z] = 0;
map[z][x] = 0;
a.e--;
}
}
a.n--;
return true; //结点数-1
}
bool del2(G &a)
{ //《删除·边》
printf("输入俩结点名称:");
int x, y, z;
char t1[20] = {}, t2[20] = {};
do
{ // 1 9 11 a b c d e f g h 德玛西亚 a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11 a
memset(t1, '\0', sizeof(t1));
memset(t2, '\0', sizeof(t2));
scanf("%s%s", &t1, &t2);
if (wrong(t1))
return false;
} while (!find(a, t1, y) || !find(a, t2, z));
//结点名称异常导致没找到
printf("%s位于%d %s位于%d,两点间直连边删除!\n", t1, y, t2, z);
map[y][z] = 0;
map[z][y] = 0; //地图权值赋予
a.e--;
return true;
}
bool insert_edge(G &a)
{ //《插入·边》
int n, s, x, y, z;
char t1[20] = {}, t2[20];
printf("输入修改条数:");
scanf("%d", &n);
printf("输入无向边(俩结点名称·空格隔开+边权)\n");
for (x = 1; x <= n; x++)
{
do
{
memset(t1, '\0', sizeof(t1));
memset(t2, '\0', sizeof(t2));
printf("%d号边:", x);
scanf("%s%s%d", &t1, &t2, &s);
} while (!find(a, t1, y) || !find(a, t2, z) || s == 0);
//结点名称异常导致没找到,或者已经存在边!=1,或者边=0
printf(" %s位于%d %s位于%d 建立无向边权值=%d\n", t1, y, t2, z, s);
map[y][z] = s;
map[z][y] = s; //地图权值赋予
}
return true;
}
bool insert_node(G &a)
{ //《插入·点》
int x = 1, y, z;
while (1)
{
if (strlen(a.node[x]) != 0)
x++; // 1 4 4 a b c d a b 1 b c 4 a c 2 a d 3
else
break;
}
printf("探查到插入点:%d\n", x);
printf("输入结点名称:");
scanf("%s", a.node[x]);
a.n++;
return true;
}
bool trace_1(G a)
{ //《探测·单点》
char t1[20] = {};
int x, y, z = 0;
printf("输入单点名称(必须存在):");
do
{
memset(t1, '\0', sizeof(t1));
scanf("%s", &t1);
} while (!find(a, t1, y));
printf("追踪到结点%s,存储区位于node<%d>\n", t1, y);
for (x = 1; x <= nmax; x++)
if (map[x][y] != 0 && !pd2(a, x))
{ //不是被删除的点 且 路径存在
printf(" 连接结点%s,权值%d\n", a.node[x], map[x][y]);
z++;
}
printf("共有%d条边;\n", z);
return true;
}
bool trace_2(G a)
{ //《探测·双点》
char t1[20] = {}, t2[20] = {};
int x, y, z;
printf("输入俩点名称(必须存在·空格隔开):");
do
{
memset(t1, '\0', sizeof(t1));
memset(t2, '\0', sizeof(t2));
scanf("%s%s", &t1, &t2); // 1 8 11 a b c d e f g h a h 1 a b 2 b c 3 c d 4 h f 5 f b 6 e b 7 c e 8 g d 9 f g 10 h d 11
} while (!find(a, t1, y) || !find(a, t2, z));
printf("追踪到结点%s,存储区位于node<%d>\n追踪到结点%s,存储区位于a.node<%d>\n", t1, y, t2, z);
printf("选择最短路径探测方式(Dijkstra/Floyd):");
scanf("%d", &x);
if (x == 1)
Dijkstra(a, y, z);
if (x == 2)
Floyd(a, y, z);
return true;
}
bool menu(int &x, G a)
{ //《菜单·图情况汇报》
system("cls");
float z;
int y;
alone = 0; // printf("%d\n",maxx);
if (a.n > nmax)
nmax = a.n;
printf("【当前图·汇报】");
if (!empty(a))
{
printf(":node=%d,edge=%d,", a.n, a.e);
if (loop(a))
printf("存在回路");
else
printf("不存在回路");
if (!alone)
printf(",是连通图");
else
printf(",非连通图,有%d个孤立点", alone);
if (star != 0)
printf(",启动结点<%s>于%d\n", a.node[star], star);
else
printf(",尚未设置启动结点\n");
printf("\nDFS:");
DFS(a, star);
printf("\nBFS:");
BFS(a, star);
printf("\ntop_sort:");
top_sort(a, star);
z = a.e * log(a.e);
y = (int)z;
printf("\n最小生成树,node<%d> edge<%d>\n", a.n * a.n, y);
if (LT)
{
printf("Kruskal:");
Kruskal(a);
printf("\nPrim:");
Prim(a);
}
else
printf("不是连通图,无法生成最小生成树!DFS、BFS不完全!!\n");
mapp(a);
}
else
printf("这是个空图!");
printf("\n\n");
printf("《最短路径 ·双点》:Dijkstra/Floyd算法(邻接表)(矩阵流)\n");
printf("《最小生成树·全图》:Kruskal /Prim 算法(eloge) (n&2)【自适应】\n");
printf("《拓扑排序 ·全图》\n\n");
printf("1-创建 2-删除·点 3.删除·边 0-初始化\n");
printf("4-启点更迭 5-探测·点 6-探测·双(最短路径)\n");
printf("7-插入或修改边 8-插入点\n");
printf("您选择:");
scanf("%d", &x);
}
//『寒月竹影江浸灭,孤雁剑与暮风随』 影月·暮风
//『悠婉流莺花底滑,银霞笛曲荷风晚』 夏栀·荷风
int main()
{
G a;
int x, y, z;
init(a);
char t[20] = {};
while (1)
{
menu(x, a);
switch (x)
{
case 0:
{ //《初始化》
init(a);
break;
}
case 1:
{ //《创建》
create(a);
break;
}
case 2:
{ //《删除·点》
del1(a);
break;
}
case 3:
{ //《删除·边》
del2(a);
break;
}
case 4:
{ //《启动更迭》
go_star(a);
break;
}
case 5:
{ //《探测·单点》
trace_1(a);
break;
}
case 6:
{ //《探测·双点》
trace_2(a);
break;
}
case 7:
{ //《覆盖·单边》 //兼顾 插入/修改功能
insert_edge(a);
break;
}
case 8:
{ //《插入·单点》
insert_node(a);
break;
}
default:
{ //输入异常
printf("读入异常!\n");
break;
}
}
printf("\n");
system("pause");
}
return 0;
}