最小生成树和最短路

//是邻接矩阵的无向图
/*测试样例
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值