实验5——图及其应用

图的邻接矩阵实验

第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;   	
}

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值