3.求最小生成树的权值和
【问题描述】
已知含有n个顶点(编号从1开始)的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出 (三元组数据结构见教材5.3.2节),只给出不包括主对角线元素在内的下三角这部分的元素,且不包括不邻接的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
第1行给出图中结点个数n和三元组的个数num,之后每行给出一个三元组,数之间用1个空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
求解的最小生成树的各条边、各边的权值、最小生成树的权值和
【样例输入】
5 8
2 1 7
3 1 6
3 2 8
4 1 9
4 2 4
4 3 6
5 2 4
5 4 2
【样例输出】
1-3:6
3-4:6
4-5:2
4-2:4
18
【样例说明】
权值是正整数,可能很大,但不需要考虑整型溢出问题
#include<iostream>
using namespace std;
#define MAX 99999//定义一个值来代表无穷大
#define MAXNUM 100
typedef struct AdjMatrix
{
int vexnum,arcnum;
int arcs[MAXNUM][MAXNUM];
}AdjMatrix;
typedef struct a
{
int adjvex;
int lowcost;
}closedge;
AdjMatrix g;
void CreateGraph(AdjMatrix &g)
{
int i,j;
int a,b,c;
cin>>g.vexnum>>g.arcnum;
for(i=1;i<=g.vexnum;i++)
{
for(j=1;j<=g.vexnum;j++)
{
g.arcs[i][j]=MAX;
}
}
for(i=1;i<=g.arcnum;i++)
{
cin>>a>>b>>c;
g.arcs[a][b]=c;
g.arcs[b][a]=c;
}
}
int Minium(closedge c[])//找最小值
{
int Min=MAX,Mini;
for(int i=1;i<=g.vexnum;i++)
{
if(c[i].lowcost!=0&&c[i].lowcost<Min)
{
Min=c[i].lowcost;
Mini=i;
}
}
return Mini;
}
void MiniSpanTree_Prim(AdjMatrix g,int u=1)//prim算法
{
int sum=0;
closedge c[MAXNUM+1];
c[u].lowcost=0;//u到自己的权值为0
for(int i=1;i<=g.vexnum;i++)//赋值
{
if(i!=u)
{
c[i].adjvex=u;
c[i].lowcost=g.arcs[u][i];
}
}
for(int e=1;e<=g.vexnum-1;e++)
{
int v=Minium(c);
sum+=c[v].lowcost;
cout<<c[v].adjvex<<"-"<<v<<":"<<c[v].lowcost<<endl;
c[v].lowcost=0;
for(int i=1;i<=g.vexnum;i++)
{
if(g.arcs[v][i]<c[i].lowcost)
{
c[i].lowcost=g.arcs[v][i];
c[i].adjvex=v;
}
}
}
cout<<sum<<endl;
}
int main()
{
CreateGraph(g);
MiniSpanTree_Prim(g,1);
return 0;
}
5.拓扑排序
【问题描述】
拓扑排序的流程如下:
1. 在有向图中选一个没有前驱的顶点并且输出之;
2. 从图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止。后一种情况则说明有向图中存在环。
采用邻接表存储有向图(可参考本次实验第2题代码),并通过栈来暂存所有入度为零的顶点。拓扑排序算法请参考教材上算法7.11和7.12或课件上的相应算法。
在本题中,读入一个有向图的信息(输入形式同本次实验第2题,详见下述【输入形式】),建立有向图并按照上述算法判断此图是否有回路,如果没有回路则输出拓扑有序的顶点数据序列。顶点的数据类型为int型。
注意:顶点编号从0开始。
【输入形式】仿照算法7.2的输入:
第1行输入图的结点个数n。第2行是图的各顶点数据。
之后的若干行(有向图为e行, 无向图为2e行) 依次输入各条边的弧尾、弧头的顶点编号。注意:因为算法7.2是按头插法建边链表的,所以要使得到的每个边链表中 都是按照邻接顶点的编号由小到大的顺序链接存储,就必须输入各边的顺序 首先是按照弧尾编号由小到大的顺序,并且输入弧尾相同的各边时 按照弧头顶点编号由大到小的顺序输入这些边,具体见样例输入。
最后一行输入-1和-1表示输入结束。
【输出形式】
如果读入的有向图含有回路,请输出“ERROR”,不包括引号。
如果读入的有向图不含有回路,请按照题目描述中的算法依次输出图的拓扑有序序列,每个整数后输出一个空格。
请注意行尾输出换行。
【样例输入】
4
0(空格)1(空格)2(空格)3
0(空格)1
1(空格)2
3(空格)2
-1(空格)-1
【样例输出】
3(空格)0(空格)1(空格)2(空格)
【说明】
本题中,需要严格的按照题目描述中的算法进行拓扑排序,并在排序的过程中将顶点数据先依次存储下来,直到最终能够判定有向图中不含回路之后,才能够进行输出,否则不能通过测试数据。
#include<iostream>
#include<stack>
using namespace std;
#define MAXNUM 200
typedef struct ArcNode//边
{
int adjvex;
struct ArcNode *nextarc;
}ArcNode;
typedef struct VertexNode//点
{
int info;
ArcNode *firstarc;
}VertexNode;
typedef struct//邻接表
{
VertexNode vertex[MAXNUM];
int vexnum,arcnum;
}AdjList;
void Create(AdjList &g)//创建邻接表
{
int x,y;
g.vexnum=g.arcnum=0;
cin>>g.vexnum;
for(int i=0;i<g.vexnum;i++)
{
g.vertex[i].firstarc=NULL;
}
for(int i=0;i<g.vexnum;i++)
{
cin>>g.vertex[i].info;
}
while(cin>>x>>y)
{
if(x==-1&&y==-1) break;
ArcNode *p1=NULL;
p1=new ArcNode;
p1->adjvex=y;
p1->nextarc=g.vertex[x].firstarc;
g.vertex[x].firstarc=p1;
g.arcnum++;
}
}
void FindID(AdjList G,int indegree[MAXNUM])//将每个结点的度存入indegree数组中
{
int i;
ArcNode *p=NULL;
for(i=0;i<G.vexnum;i++)
indegree[i]=0;
for(i=0;i<G.vexnum;i++)
{
p=G.vertex[i].firstarc;
while(p!=NULL)
{
indegree[p->adjvex]++;
p=p->nextarc;
}
}
}
void TopoSort(AdjList G)//拓扑排序
{
stack<int> S;
int indegree[MAXNUM];
int i,Count,k;
int sorted[100]={0};
ArcNode *p;
FindID(G,indegree);
for(i=0;i<G.vexnum;i++)
{
if(indegree[i]==0) S.push(i);
}
Count=0;
while(!S.empty())
{
i=S.top();
S.pop();
sorted[Count]=G.vertex[i].info;
Count++;
p=G.vertex[i].firstarc;
while(p!=NULL)
{
k=p->adjvex;
indegree[k]--;
if(indegree[k]==0) S.push(k);
p=p->nextarc;
}
}
if(Count<G.vexnum) cout<<"ERROR"<<endl;
else
{
for(i=0;i<Count;i++)
{
cout<<sorted[i]<<" ";
}
}
}
int main()
{
AdjList g;
Create(g);
TopoSort(g);
return 0;
}