//是邻接矩阵的无向图
/*测试样例
6 10
a b c d e f
a b 6
a c 1
a d 5
b c 5
b e 3
c d 5
c e 6
c f 4
d f 2
e f 6
*/
#include<bits/stdc++.h>
using namespace std;
#define MaxVertexNum 100 //顶点数目最大值
//typedef char VertexType; //顶点的数据类型
//typedef int EdgeType; //带权图中边上权值的数据类型
const int INF=0x3f3f3f3f;
typedef struct
{
char Vex[100]; //顶点表
int Edge[100][100]; //邻接矩阵,边表
int vexnum, edgenum; //图的顶点数和弧数
}MGraph;
//用于Kruskal
struct edge{
int u,v,w; //边的顶点,权值
}edges[110];
char mpp[110];
int ww[100][100];//用于dijkstra和floyd
//MGraph G;
unordered_map<char,int>mp;
/***********创建无向图************/
void create_Graph2(MGraph *G)
{
int i, j;
char start, endd; //边的起点序号、终点序号
int numV, numE;
int w; //边上的权值
char ch;
printf("请输入所创建图的顶点数和边数(用空格隔开):");
scanf("%d%d", &numV, &numE);
ch=getchar();//上面的顶点数和边数输入完成后,会按一次enter键,这里的ch用于"吸收"enter防止对下一步输入造成影响
G->vexnum = numV;
G->edgenum = numE;
//图的初始化
for (i = 0; i < G->vexnum; i++)
{
for (j = 0; j < G->vexnum; j++)
{
if (i == j)
G->Edge[i][j] = 0;
else
G->Edge[i][j] = 32767;
}
}
//顶点信息存入顶点表
for (i = 0; i < G->vexnum; i++)
{
printf("请输入第%d个顶点的信息:", i + 1);
//ch=getchar();
//scanf("%c", G->Vex[i]);
cin>>G->Vex[i];
mp[G->Vex[i]]=i;
mpp[i]=G->Vex[i];
ch=getchar();
}
for(int i=1;i<=G->vexnum;i++)
{
for(int j=1;j<=G->vexnum;j++)
{
if(i==j) ww[i][j]=0;
ww[i][j]=32767;
}
}
//输入无向图边的信息
for (i = 0; i < G->edgenum; i++)
{
printf("请输入边的起点序号,终点序号,权值(用空格隔开):");
//scanf("%c %c %d", &start, &endd, &w);
cin>>start>>endd>>w;
ch=getchar();
G->Edge[mp[start]][mp[endd]] = w; //有向图只在这里不一样
G->Edge[mp[endd]][mp[start]] = w;
//用于Kruskal
edges[i].u=mp[start]+1;
edges[i].v=mp[endd]+1;
edges[i].w=w;
//用于dijkstra
ww[mp[start]+1][mp[endd]+1]=w;
}
}
/***********打印出邻接矩阵*********/
void print_Matrix(MGraph G)
{
int i, j;
char ch;
printf("\n图的顶点为:");
for (i = 0; i < G.vexnum; i++)
{
//printf("%c ", G.Vex[i]);
cout<<G.Vex[i]<<' ';
}
printf("\n输出邻接矩阵:\n");
printf("\t");
for (i = 0; i < G.vexnum; i++)
//printf("\t%c", G.Vex[i]);
cout<<'\t'<<G.Vex[i]<<'\t';
for (i = 0; i < G.vexnum; i++)
{
//printf("\n\n%c", G.Vex[i]);
cout<<endl<<endl<<G.Vex[i];
for (j = 0; j < G.vexnum; j++)
{
if (G.Edge[i][j] == 32767)
printf("\t%9s", "∞");
else
printf("\t%9d", G.Edge[i][j]);
}
printf("\n");
}
}
unordered_map<char,bool>stt;
void dfs(MGraph G,char u)
{
cout<<u<<' ';
stt[u]=true;
for(int i=0;i<G.vexnum;i++)
{
if(!stt[G.Vex[i]] && G.Edge[mp[u]][i]!=32767)
{
dfs(G,G.Vex[i]);
}
}
}
void bfs(MGraph G)
{
unordered_map<char,bool>st;
for(int i=0;i<G.vexnum;i++) st[G.Vex[i]]=false;
queue<char>q;//队列里面存的是结点的符号abcd
q.push(G.Vex[0]);//图的起点先放到队列里
st[G.Vex[0]]=true;//进过队的就标记上
while(q.size())
{
auto t=q.front();//找到队首元素
cout<<t<<' ';
q.pop();//队首出队
for(int i=0;i<G.vexnum;i++)
{
if(!st[G.Vex[i]] && G.Edge[mp[t]][i]!=32767)//如果那个点它之前没有被遍历过并且队首那个可以走到他
{
q.push(G.Vex[i]);//就把他进队
st[G.Vex[i]]=true;
}
}
}
}
typedef struct
{
int adjvex;
int lowcost;
}closedge;
void Prim(MGraph G)
{
int v=0;//初始节点
closedge C[100];
int mincost = 0; //记录最小生成树的各边权值之和
//初始化
for (int i = 0; i < G.vexnum; i++)
{
C[i].adjvex = v;
C[i].lowcost = G.Edge[v][i];
}
cout << "最小生成树的所有边:"<< endl;
//初始化完毕,开始G.vexnum-1次循环
for (int i = 1; i < G.vexnum; i++)
{
int k;
int min = INF;
//求出与集合U权值最小的点 权值为0的代表在集合U中
for (int j = 0; j<G.vexnum; j++)
{
if (C[j].lowcost != 0 && C[j].lowcost<min)
{
min = C[j].lowcost;
k = j;
}
}
//输出选择的边并累计权值
cout << "(" << G.Vex[C[k].adjvex] << "," << G.Vex[k] <<") ";
mincost += C[k].lowcost;
//更新最小边
for (int j = 0; j<G.vexnum; j++)
{
if (C[j].lowcost != 0 && G.Edge[k][j]<C[j].lowcost)
{
C[j].adjvex = k;
C[j].lowcost= G.Edge[k][j];
}
}
}
cout << "最小生成树权值之和:" << mincost;
}
int parent[110];
int n,m;
//初始化并查集
void UFset()
{
for(int i=1; i<=n; i++) parent[i] = -1;
}
//查找i的根
int find(int i)
{
int temp;
//查找位置
for(temp = i; parent[temp] >= 0; temp = parent[temp]);
//压缩路径
while(temp != i)
{
int t = parent[i];
parent[i] = temp;
i = t;
}
return temp;
}
//合并两个元素a,b
void merge(int a,int b)
{
int r1 = find(a);
int r2 = find(b);
int tmp = parent[r1] + parent[r2]; //两个集合节点数的和
if(parent[r1] > parent[r2])
{
parent[r1] = r2;
parent[r2] = tmp;
}
else
{
parent[r2] = r1;
parent[r1] = tmp;
}
}
int cmp(const void * a, const void * b)
{
edge * e1 = (edge *)a;
edge * e2 = (edge *)b;
return e1->w - e2->w;
}
void Kruskal(MGraph G)
{
//先将所有边按照权重从小到大排序
//枚举每一条边a-b权重为c,如果a和b不在一个集合里就把它俩加在一个集合里面
n=G.vexnum;m=G.edgenum;//n是点数,m是边数
//sort(edges,edges+m,cmp);
qsort(edges, m, sizeof(edge), cmp);//按照权重从小到大排序
int sumWeight=0;
//int num=0;
UFset();//并查集初始化
cout<<"最小生成树的所有边:"<<endl;
for(int i=0; i<m; i++)
{
int u = edges[i].u;
int v = edges[i].v;
if(find(u) != find(v))
{ //u和v不在一个集合
//printf("(%c,%c) 权值: %d", mpp[u],mpp[v],edges[i].w);
cout<<'('<<mpp[u-1]<<','<<mpp[v-1]<<')';
cout<<"该边权值为:"<<edges[i].w<<endl;;
sumWeight+=edges[i].w;
//num ++;
merge(u, v); //把这两个边加入一个集合。
}
}
printf("最小生成树的权值之和为:%d", sumWeight);
}
void dijkstra(MGraph G)
{
int nn,mm;
nn=G.vexnum;mm=G.edgenum;//n是点数,m是边数
int dist[100];//dist[i]表示1到i的距离
bool st[100];//判断某个点是否已经找到最短的路
for(int i=1;i<=nn;i++) dist[i]=32767;
memset(st,0,sizeof(st));
dist[1]=0;
for(int i=1;i<=nn;i++)
{
int t=-1;
for(int j=1;j<=nn;j++)
{
if(!st[j] && (dist[j]<dist[t]||t==-1))
{
t=j;
}
}
st[t]=true;
for(int j=1;j<=nn;j++)
{
if(!st[j] && dist[j]>dist[t]+ww[t][j])
{
dist[j]=dist[t]+ww[t][j];
}
}
}
for(int i=1;i<=nn;i++)
{
printf("从起点%c到%c的最短距离是:%d",mpp[0],mpp[i-1],dist[i]);
if(i<nn) printf("\n");
}
}
void floyd(MGraph G)
{
int nn,mm;
nn=G.vexnum;mm=G.edgenum;//n是点数,m是边数
int www[110][110];
for(int i=1;i<=nn;i++)
{
for(int j=1;j<=nn;j++)
{
www[i][j]=ww[i][j];
}
}
for(int k=1;k<=nn;k++)
{
for(int i=1;i<=nn;i++)
{
for(int j=1;j<=nn;j++)
{
www[i][j]=min(www[i][j],www[i][k]+www[k][j]);
}
}
}
for(int i=1;i<=nn;i++)
{
for(int j=1;j<=nn;j++)
{
if(www[i][j]!=32767 && www[i][j]) printf("%c到%c的最短距离为 %d\n",mpp[i-1],mpp[j-1],www[i][j]);
}
}
}
int main()
{
MGraph G;
create_Graph2(&G);
//print_Matrix(G);
printf("请输入你的操作数,\n输入1得dfs,\n输入2得bfs,\n输入3prim得到的最小生成树,\n输入4kruskal得到的最小生成树,\n输入5得dijkstra最短路答案,\n输入6得floyd多源最短路:\n");
int op;
while(cin>>op)
{
for(int i=0;i<G.vexnum;i++) stt[G.Vex[i]]=false;
if(op==1) dfs(G,G.Vex[0]);
else if(op==2) bfs(G);
else if(op==3) Prim(G);
else if(op==4) Kruskal(G);
else if(op==5) dijkstra(G);
else if(op==6) floyd(G);
else cout<<"输入的操作做不了";
cout<<endl;
}
system("pause");
return 0;
}
最小生成树和最短路
最新推荐文章于 2024-09-25 13:54:13 发布