图的邻接矩阵实验
第1关:建立无向网的邻接矩阵
任务描述
本关任务:建立无向网的邻接矩阵。
相关知识
1.无向网的定义 2.无向网的邻接矩阵
编程要求
本关任务是实现右侧编辑栏里面的代码编写,实现无向网的邻接矩阵的建立。
输入格式:
第1行:顶点数n和边数m 第2行:输入n个字符,表示顶点的名称 接下来的m行,依次输入每条边
输出格式:
第1行:图的邻接矩阵: 其后的m行为图的邻接矩阵(其中∞表示无穷大)
#include <cstdio>
#include <iostream>
using namespace std;
#define MaxInt 32767 //最大值
#define MVNum 20 //最大顶点数
typedef struct {
int vexnum,arcnum; //顶点数和边的数目
char vexs[MVNum]; //顶点向量
int arcs[MVNum][MVNum]; //邻接矩阵
} AMGraph;
int LocateVex(AMGraph G, char v) {
int i;
for (i = 0; i < G.vexnum; i++)
if (G.vexs[i] == v) return i;
return -1;
}
void CreateUDN(AMGraph &G) //创建无向网的邻接矩阵
{
cin >> G.vexnum >> G.arcnum;
for (int i = 0; i < G.vexnum; i++) {
cin >> G.vexs[i];
}
// 初始化邻接矩阵
for (int i = 0; i < G.vexnum; i++) {
for (int j = 0; j < G.vexnum; j++) {
if(i==j)
G.arcs[i][j] = 0;
else
G.arcs[i][j] = MaxInt;
}
}
for (int k = 0; k < G.arcnum; k++) {
char v1, v2;
int w;
cin >> v1 >> v2 >> w;
int i = LocateVex(G, v1);
int j = LocateVex(G, v2);
if (i != -1 && j != -1) {
G.arcs[i][j] = w;
G.arcs[j][i] = w; // 无向图,对称矩阵
}
// else {
// cout << "输入顶点名称有误!" << endl;
// k--; // 重新输入当前边
// }
}
}
void PrintGraph(AMGraph G) //输出图的邻接矩阵
{
cout << "图的邻接矩阵:";
for (int i = 0; i < G.vexnum; i++) {
cout << endl;
for (int j = 0; j < G.vexnum; j++) {
if (G.arcs[i][j] == MaxInt)
printf(" ∞");
else
printf("%5d", G.arcs[i][j]);
}
}
}
int main()
{
AMGraph G;
CreateUDN(G);
PrintGraph(G);
return 0;
}
第2关:有向图的深度优先遍历
任务描述
本关任务:建立有向图的邻接矩阵,实现图的深度优先遍历算法。(约定:从编号小的顶点开始遍历)
相关知识
1.有向图的邻接矩阵 2.图的深度优先遍历
编程要求
实现右侧编辑栏里面的代码编写,建立有向图的邻接矩阵的建立,以及图的深度优先遍历。
输入格式
第1行:输入顶点数n和边数m 第2行:输入n个字符(表示顶点的名称) 接下来m行依次输入每条有向边
输出格式
1.有向图的邻接矩阵 2.图的深度优先序列(如图连通,则输出一行,否则分多行输出。注:每个字符前有一个空格。)
#include <iostream>
#include<stdio.h>
using namespace std;
#define MaxInt 32767 //最大值
#define MVNum 20 //最大顶点数
typedef struct {
int vexnum,arcnum; //顶点数和弧的数目
char vexs[MVNum]; //顶点向量
int arcs[MVNum][MVNum]; //邻接矩阵
}AMGraph;
int LocateVex(AMGraph G, char v) {
int i;
for (i = 0; i < G.vexnum; i++)
if (G.vexs[i] == v) return i;
return -1;
}
void CreateDG(AMGraph& G)
{//创建有向图的邻接矩阵
/****************begin****************/
cin >> G.vexnum >> G.arcnum;
for (int i = 0; i < G.vexnum; i++)
cin >> G.vexs[i];
for (int i = 0; i < G.vexnum; i++)
{
for (int j = 0; j < G.vexnum; j++)
G.arcs[i][j] = 0;
}
char v1, v2;
for (int i = 0; i < G.arcnum; i++)
{
cin >> v1 >> v2;
int p1 = LocateVex(G, v1);
int p2 = LocateVex(G, v2);
G.arcs[p1][p2] = 1;
}
/****************end*****************/
}
void PrintGraph(AMGraph G) //输出图的邻接矩阵
{
cout<<"有向图的邻接矩阵:";
for (int i=0;i<G.vexnum;i++)
{ cout<<endl;
for (int j=0;j<G.vexnum;j++)
{
printf("%5d",G.arcs[i][j]);
}
}
}
//深度优先搜索DFS
bool visited[MVNum];
void DFS(AMGraph G, int v)
{
cout << " "<< G.vexs[v]; // 访问顶点v
visited[v] = true; // 标记顶点v已访问
for (int i = 0; i < G.vexnum; i++)
{
if (G.arcs[v][i] == 1 && !visited[i])
{
DFS(G, i); // 递归访问未访问的相邻顶点
}
}
}
void DFSTraverse(AMGraph G)
{
for (int i = 0; i < G.vexnum; i++)
{
visited[i] = false; // 初始化visited数组
}
for (int i = 0; i < G.vexnum; i++)
{
if (!visited[i])
{
DFS(G, i);
cout << endl;
}
}
}
int main()
{
AMGraph G;
CreateDG(G); //建立有向图的邻接矩阵
PrintGraph(G); //输出图的邻接矩阵
cout<<"\n图的深度优先序列:\n";
DFSTraverse(G);
return 0;
}
第3关:prim算法求最小生成树
任务描述
本关任务:编程实现无向连通网最小生成树的prim算法。
相关知识
1.无向连通网的建立 2.最小生成树的定义 3.求解最小生成树的prim算法(参见教材:P161)
编程要求
在右侧编辑栏中填写代码,实现prim算法,按步骤输出每条边,以及最小生成树的代价。
输入说明
第1行:输入顶点数n和边数m 第2行:输入n个字符(表示顶点的名称) 接下来的m行,输入每条边(u,v),以及边上的权值。 最后输入求解最小生成树的起始顶点
输出说明
1.输出图的邻接矩阵 2.依次输出最小生成树的每条边(i,j)及其权值。3.最后输出最小生成树的代价。
#include <cstdio>
#include <iostream>
using namespace std;
#include "graph.h" //图的定义、无向网的建立以及输出函数
typedef struct{
char adjvex;
int lowcost;
}node;
node closedge[MVNum]; //定义待选边辅助数组
int Min(AMGraph G)
{ //从待选边辅助数组closeedge中选择最小边closedge[k],返回k
int k = 0;
while (closedge[k].lowcost == 0) {
k++;
}
int minIndex = k;
for (int i = k + 1; i < G.vexnum; i++) {
if (closedge[i].lowcost != 0 && closedge[i].lowcost < closedge[minIndex].lowcost) {
minIndex = i;
}
}
return minIndex;
}
int MiniSpanTree(AMGraph G, char u)
{ //从顶点u出发构造最小生成树T,输出T的各条边,函数返回T的代价
int MSTcost=0;
int k = LocateVex(G, u);
for (int i = 0; i < G.vexnum; i++) {
if (i != k) {
closedge[i].adjvex = u;
closedge[i].lowcost = G.arcs[k][i];
}
}
closedge[k].lowcost = 0;
for (int i = 1; i < G.vexnum; i++) {
int minIndex = Min(G);
cout << "(" << closedge[minIndex].adjvex << ","<< G.vexs[minIndex] << ")" << " "<<closedge[minIndex].lowcost<< endl;
MSTcost+=closedge[minIndex].lowcost;
closedge[minIndex].lowcost = 0;
for (int j = 0; j < G.vexnum; j++) {
if (G.arcs[minIndex][j] < closedge[j].lowcost) {
closedge[j].adjvex = G.vexs[minIndex];
closedge[j].lowcost = G.arcs[minIndex][j];
}
}
}
return MSTcost;
}
int main()
{
AMGraph G;
char u;
int MSTcost;
CreateUDN(G); //建立无向网的邻接矩阵
cin>>u; //输入起始顶点
PrintGraph(G); //输出无向网
cout<<"\n\n最小生成树的边:\n";
MSTcost=MiniSpanTree(G,u); // 从顶点u出发构造最小生成树T
cout<<"\n最小生成树的代价:\n"<<MSTcost;
return 0;
}
第4关:Dijkstra算法求解单源点最短路径
#include <cstdio>
#include <iostream>
using namespace std;
#include "graph.h" //图的定义、 有向网的建立以及输出函数
int FindMinDist(AMGraph G,int dist[],int v0)
{
int min=MaxInt;
int index;
for(int i=0;i<G.vexnum;i++)
{
if(i!=v0 && dist[i]<min)
{
min=dist[i];
index=i;
}
}
return index;
}
void ShortestPath_DIJ(AMGraph G, int v0)
{
int dist[MVNum];
bool visited[MVNum];
for (int i = 0; i < G.vexnum; i++) {
dist[i] = G.arcs[v0][i];
visited[i] = false;
}
visited[v0] = true;
dist[v0] = 0;
for (int i = 1; i < G.vexnum; i++)
{
int minDist = MaxInt, u = -1;
for (int j = 0; j < G.vexnum; j++)
{
if (!visited[j] && dist[j] < minDist)
{
minDist = dist[j];
u = j;
}
}
if (u == -1) break;
visited[u] = true;
for (int v = 0; v < G.vexnum; v++) {
if (!visited[v] && (dist[u] + G.arcs[u][v] < dist[v])) {
dist[v] = dist[u] + G.arcs[u][v];
}
}
}
for (int i = 0; i < G.vexnum; i++)
{
int index=FindMinDist(G,dist,v0);
if(dist[index]!=MaxInt)
{
cout << G.vexs[v0] << "-->" << G.vexs[index] << " " << dist[index] << endl;
dist[index]=MaxInt;
}
}
}
int main()
{
AMGraph G;
char u;
CreateDN(G); //建立有向网的邻接矩阵
cin>>u; //输入源点
PrintGraph(G); //输出有向网的邻接矩阵
int v0=LocateVex(G,u);
cout<<"\n从顶点"<<u<<"到图中其他顶点的最短路径:\n" ;
ShortestPath_DIJ(G,v0); //从顶点v0开始,应用dijkstra算法求最短路径
return 0;
}
图的邻接表实验
第1关:建立图的邻接表
#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include <iostream>
using namespace std;
#define MVNum 20 //最大顶点数
typedef struct ArcNode { //边结点
int adjvex; //邻接点的位置
struct ArcNode* nextarc; //指向下一条边的指针
}ArcNode;
typedef struct VNode { //表头结点(顶点信息)
char data; //顶点值
ArcNode* firstarc; //指向第一条依附该顶点的边的指针
}VNode;
typedef struct {
int vexnum; //图的顶点数
int arcnum; //图的边数
VNode vertices[MVNum]; //顶点向量表
}ALGraph; //邻接表
int LocateVex(ALGraph G, char v)
{//在顶点向量表中查找顶点v,如果找到,则返回顶点在图中的位置,否则返回-1
for (int i = 0; i < G.vexnum; i++)
if (G.vertices[i].data == v) return i;
return -1;
}
void CreateUDG(ALGraph& G)
{//建立无向图的邻接表 , 对每一条边(i,j),按照头插法,分别将表结点插入i表和j表
/******************begin*****************/
scanf("%d %d", &G.vexnum, &G.arcnum);
for (int i = 0; i < G.vexnum; i++)
{
cin >> G.vertices[i].data;
G.vertices[i].firstarc = NULL;
}
for (int i = 0; i < G.arcnum; i++)
{
char v1, v2;
cin >> v1 >> v2;
int p1 = LocateVex(G, v1);
int p2 = LocateVex(G, v2);
ArcNode* node1 = new ArcNode;
node1->adjvex = p2;
node1->nextarc = G.vertices[p1].firstarc;
G.vertices[p1].firstarc = node1;
ArcNode* node2 = new ArcNode;
node2->adjvex = p1;
node2->nextarc = G.vertices[p2].firstarc;
G.vertices[p2].firstarc = node2;
}
/******************end ******************/
}
void PrintGraph(ALGraph G) //输出图中每个点的邻接点
{
ArcNode* p;
for (int i = 0; i < G.vexnum; i++)
{
printf("\n%2c邻接到:", G.vertices[i].data);
for (p = G.vertices[i].firstarc; p; p = p->nextarc)
{
int j = p->adjvex;
printf("%2c", G.vertices[j].data);
}
}
}
int main()
{
ALGraph G;
CreateUDG(G); //建立无向图的邻接表
PrintGraph(G); //输出图的邻接表
return 0;
}
第2关:计算顶点的出度和入度
#include <cstdio>
#include <iostream>
using namespace std;
#include "graph.h" //图的邻接表定义、有向图邻接表的建立和输出
void FindOutdegree(ALGraph G,int outdegree[])
{ //计算每个顶点的出度,存入数组outdegree
/******************begin*****************/
int i,j=0;
for(i=0;i<G.vexnum;i++)
{
int od=0;
ArcNode* p=G.vertices[i].firstarc;
while(p!=NULL)
{
od++;
p=p->nextarc;
}
outdegree[j++]=od;
}
/******************end *****************/
}
void FindIndegree(ALGraph G,int indegree[])
{ //计算每个顶点的入度,存入数组indegree
/******************begin*****************/
int i;
for(i=0;i<G.vexnum;i++)
{
ArcNode* p=G.vertices[i].firstarc;
while(p!=NULL)
{
indegree[p->adjvex]++;
p=p->nextarc;
}
}
/******************end *****************/
}
int main()
{ ALGraph G;
int indegree[MVNum]={0},outdegree[MVNum];
CreateDG(G); //建立有向图的邻接表
PrintGraph(G); //输出图的邻接表
FindOutdegree(G,outdegree); //计算每个顶点的出度
cout<<"\n 顶点的出度:";
for (int i=0;i<G.vexnum;i++)
printf("%2d",outdegree[i]);
FindIndegree(G,indegree); //计算每个顶点的入度
cout<<"\n 顶点的入度:";
for (int i=0;i<G.vexnum;i++)
printf("%2d",indegree[i]) ;
return 0;
}
第3关:图的广度优先遍历
#include <cstdio>
#include <iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
#include "queue.h" //循环队列的定义以及基本算法(初始化、入队、出队、判队空)
#include "graph.h" //图的邻接表定义、无向图邻接表的建立和输出
bool visited[MVNum]; //定义访问标记数组
void BFS(ALGraph G, int v)
{
SqQueue Q;
InitQueue(Q);
visited[v] = true;
cout << " " << G.vertices[v].data;
EnQueue(Q, v);
while (!QueueEmpty(Q))
{
DeQueue(Q, v);
for (ArcNode *p = G.vertices[v].firstarc; p; p = p->nextarc)
{
int w = p->adjvex;
if (!visited[w])
{
visited[w] = true;
cout << " " << G.vertices[w].data;
EnQueue(Q, w);
}
}
}
}
void BFSTraverse(ALGraph G){
int v;
for (v=0;v<G.vexnum;v++) //初始化每个顶点的访问标记为false
visited[v]=false;
for (v=0;v<G.vexnum;v++)
{
if (!visited[v])
{
cout<<endl;
BFS(G,v); //对未访问的顶点v,调用BFS,进行广度优先搜索
}
}
}//BFSTraverse
int main()
{ ALGraph G;
CreateUDG(G); //建立无向图的邻接表
PrintGraph(G); //输出图的邻接表
cout<<"\n 图的广度优先序列:";
BFSTraverse(G); //广度优先遍历
return 0;
}
第4关:AOV网的拓扑排序
#include <cstdio>
#include <iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
#include "stack.h"//顺序栈的定义和基本函数的定义
#include "graph.h"//图的邻接表定义,以及图的建立
void FindIndegree(ALGraph G,int indegree[])
{ //计算每个顶点的入度,存入数组indegree
/*****************begin*****************/
for(int i=0;i<G.vexnum;i++)
{
for(ArcNode* p=G.vertices[i].firstarc;p;p=p->nextarc)
indegree[p->adjvex]++;
}
/*****************end******************/
}
Status ToplogicalSort(ALGraph G,int topo[])
{ //利用栈保存0入度顶点,对图进行拓扑排序。如图中有环,函数返回ERROR,否则用topo数组存储拓扑序列,函数返回OK
SqStack S; //定义顺序栈s
InitStack(S); //初始化空栈
/*****************begin*****************/
int indegree[MVNum]={0};
FindIndegree(G, indegree);
for (int i = 0; i < G.vexnum; ++i) {
if (indegree[i] == 0) {
Push(S, i);
}
}
int count = 0;
while (!StackEmpty(S)) {
int v;
Pop(S, v);
topo[count++] = v;
ArcNode* p = G.vertices[v].firstarc;
while (p) {
int w = p->adjvex;
if (--indegree[w] == 0) {
Push(S, w);
}
p = p->nextarc;
}
}
if (count != G.vexnum) {
return ERROR;
}
return OK;
/*****************end******************/
}
int main()
{ ALGraph G;
int topo[MVNum];
CreateDG(G); //建立有向图的邻接表
PrintGraph(G); //输出图的邻接表
if (ToplogicalSort(G,topo)==ERROR) //拓扑排序
cout<<"\n 图中有环,拓扑排序失败!";
else{
cout<<"\n 拓扑序列:";
for (int i=0;i<G.vexnum;i++)
printf("%2c",G.vertices[topo[i]].data);
}
return 0;
}
第5关:AOE网的关键路径
#include <cstdio>
#include <iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -1
typedef int Status;
#include "stack.h" //顺序栈的定义以及栈的基本函数(初始化、入栈、出栈、判栈空)
#include "graph.h" //图的邻接表定义、图的建立和输出函数
int topo[MVNum],ve[MVNum],vl[MVNum]; //定义拓扑序列、事件最早发生时间和最晚发生时间
int FindMintopo(ALGraph G,int topo[])
{
int min=G.vexnum;
int index;
for(int i=0;i<G.vexnum;i++)
{
if(topo[i]<min)
{
min=topo[i];
index=i;
}
}
topo[index]=G.vexnum;
return min;
}
void FindIndegree(ALGraph G,int indegree[])
{ //计算图中每个顶点的入度,存入indegree数组
/*****************begin******************/
for(int i=0;i<G.vexnum;i++)
{
for(ArcNode* p=G.vertices[i].firstarc;p;p=p->nextarc)
indegree[p->adjvex]++;
}
/******************end*******************/
}
Status ToplogicalSort(ALGraph G, int topo[]) {
SqStack S;
InitStack(S);
int indegree[MVNum]={0};
FindIndegree(G, indegree);
int count = 0; //
for (int i = 0; i < G.vexnum; ++i) {
if (indegree[i] == 0)
Push(S, i);
}
while (!StackEmpty(S)) {
int v;
Pop(S, v);
topo[count++] = v;
ArcNode* p = G.vertices[v].firstarc;
while (p) {
int w = p->adjvex;
if (--indegree[w] == 0) {
Push(S, w);
}
p = p->nextarc;
}
}
if (count != G.vexnum)
return ERROR; //
return OK;
}
void CriticalPath(ALGraph G) {
int topo[MVNum];
if (ToplogicalSort(G, topo) == ERROR)
return;
int ve[MVNum], vl[MVNum];
for (int i = 0; i < G.vexnum; ++i) {
ve[i] = 0;
}
for (int i = 0; i < G.vexnum; ++i) {
int v = topo[i];
ArcNode* p = G.vertices[v].firstarc;
while (p) {
int w = p->adjvex;
if (ve[v] + p->weight > ve[w]) {
ve[w] = ve[v] + p->weight;
}
p = p->nextarc;
}
}
for (int i = 0; i < G.vexnum; ++i) {
vl[i] = ve[G.vexnum - 1];
}
for (int i = G.vexnum - 1; i >= 0; --i) {
int v = topo[i];
ArcNode* p = G.vertices[v].firstarc;
while (p) {
int w = p->adjvex;
if (vl[w] - p->weight < vl[v]) {
vl[v] = vl[w] - p->weight;
}
p = p->nextarc;
}
}
cout<<endl;
cout << " 完成工程的最短时间为:" << ve[G.vexnum - 1] << endl;
cout << " 影响工程进度的关键活动:";
for (int i = 0; i < G.vexnum; ++i) {
int v = FindMintopo(G,topo);
ArcNode* p = G.vertices[v].firstarc;
while (p) {
int w = p->adjvex;
int e = ve[v];
int l = vl[w] - p->weight;
if (e == l) {
cout<<endl;
cout << " <" << G.vertices[v].data << "," << G.vertices[w].data << "> " << p->weight;
}
p = p->nextarc;
}
}
}
int main()
{ ALGraph G;
CreateDN(G); //建立AOE网(有向网)的邻接表
PrintGraph(G); //输出邻接表
if (ToplogicalSort(G,topo)==ERROR)
cout<<"\n 图中有环,工程计划不可行!";
else
CriticalPath(G); //求完成工程的最短时间,以及影响工程进度的关键活动
return 0;
}