《数据结构(A)》第7章“图论及其算法”基本作业与设计作业

1  作业题目

7.1 试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i<>j)。注意:算法中涉及的图的基本操作必须在此存储结构上实现。

7.2  同7.1 题要求,试基于广度优先搜索策略写一算法。

7.3 采用邻接表存储结构,编写一个判别无向图中任意给定的两个顶点之间是否存在一条长度为k的简单路径的算法。

7.4 输入任意的一个网,用普里姆(Prim)算法构造最小生成树

2  作业题目解答                    

7.1

试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i<>j)。注意:算法中涉及的图的基本操作必须在此存储结构上实现。

答:

算法思想:对于深度优先采用递归的模式,不断调用下个结点,当这一过程执行到底,不再有结点的时候,开始回溯。同时需要设立一个数组来记录是否被调用过的信息

源代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define MAXN 100  //最大边数
typedef struct ArcNode {//弧结点
  int ajdVex;    //弧终点指针位置
  ArcNode* next;     //下一条弧的指针
};

typedef struct Node {//顶点结点
  ArcNode* Arc;     //指向依附该顶点的弧指针
};

typedef struct Graph {//邻接表
  Node adjlist[MAXN];     //点集
  bool visited[MAXN];     //是否被遍历
  int n, m;    //顶点数和弧数
};

Graph* G = (Graph*)malloc(sizeof(Graph));
int i, j, k;
bool hasPath = false;

void createLink() {//创建邻接表
  printf("请输入顶点数n 弧数m:");
  scanf("%d %d", &G->n, &G->m);
  printf("创建的所有点:");
  for (i = 0; i < G->n; i++) { G->adjlist[i].Arc = 0; printf("V%d ", i); }printf("\n");
  for (j = 0; j < G->m; j++) {
    printf("第%d条弧起点编号、终点编号:", j + 1);
    scanf("%d %d", &i, &k);
    ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
    p->ajdVex = k;  //将边所指向的点编号赋值
    p->next = G->adjlist[i].Arc;
    G->adjlist[i].Arc = p;
  }
}

void setFlase() {//visited置零
  hasPath = false;
  for (i = 0; i < G->n; i++) G->visited[i] = false;
}


//深度优先算法
int DFS(ALGraph G, int n, char a, char b, int& flag) {
  DFSvisited[n] = 1;
  ArcNode* p;
  p = G.vertices[n].firstarc;
  while (p != NULL) {
    if (DFSvisited[p->adjvex] == 0) {
      if (G.vertices[p->adjvex].data == b) {
        printf("%c到%c有通路\n", a, b);
        flag = 1;
      }
      DFS(G, p->adjvex, a, b, flag);
    }
    p = p->nextarc;
  }
  return 1;
}


void existPath(int d, int z) {//两点是否连通
  G->visited[d] = true;
  ArcNode* p = G->adjlist[d].Arc;
  if (d == z)hasPath = true;
  while (p) {
    if (p->ajdVex == z)hasPath = true;
    if (!G->visited[p->ajdVex])existPath(p->ajdVex, z);
    p = p->next;
  }
}


void print_Graph() {//输出邻接表
  ArcNode* p;
  for (i = 0; i < G->n; i++) {
    p = G->adjlist[i].Arc;
    printf("V%d", i);
    while (p) {
      printf("->V%d", p->ajdVex);
      p = p->next;
    }printf("\n");
  }
}

void print_Path(int d, int z) {//输出两点连接路径
  ArcNode* p = G->adjlist[d].Arc;
  printf("路径为:V%d", d);
  while (p) {
    printf("->V%d", p->ajdVex);
    if (p->ajdVex == z)break;
    p = G->adjlist[p->ajdVex].Arc;
  }printf("\n");
}


int main() {
  createLink();
  while (true) {
    printf("\n");
    printf("请输入操作(1.打印信息 2.判断路径 3.退出):");
    int choice; scanf("%d", &choice); setFlase();
    if (choice == 1) print_Graph();
    if (choice == 2) {
      printf("请输入两点编号:"); scanf("%d %d", &i, &k); existPath(i, k);
      if (hasPath) { printf("两点连通!\n"); print_Path(i, k); }
      else printf("两点不连通!\n");
    }
    if (choice == 3)break;
  }
  return 0;
}

测试用例截屏

 运行结果截屏:

7.2 

同7.1 题要求,试基于广度优先搜索策略写一算法。

答:

源代码:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define TRUE 1
#define FALSE 0
typedef int Status;

#define MAXN 100  //最大边数
typedef struct ArcNode {//弧结点
  int ajdVex;    //弧终点指针位置
  ArcNode* next;     //下一条弧的指针
};

typedef struct Node {//顶点结点
  ArcNode* Arc;     //指向依附该顶点的弧指针
};

typedef struct Graph {//邻接表
  Node adjlist[MAXN];     //点集
  bool visited[MAXN];     //是否被遍历
  int n, m;    //顶点数和弧数
};

typedef struct QNode//链队列
{
  int data;
  struct QNode* next;
} QNode, * QueuePtr;

typedef	struct
{
  QueuePtr front;	//对头指针
  QueuePtr rear;	//队尾指针
} LinkQueue;

Graph* G = (Graph*)malloc(sizeof(Graph));
int i, j, k;
bool hasPath = false;

Status InitQueue(LinkQueue& Q)
{
  //构造一个空队列Q
  Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
  if (!Q.front)
    exit(OVERFLOW);
  Q.front->next = NULL;
  return OK;
}

Status QueueEmpty(LinkQueue Q)
{
  //判断队列是否为空
  if (Q.front->next == NULL)
    return TRUE;
  return FALSE;
}

Status EnQueue(LinkQueue& Q, int e)
{
  //插入元素e为Q的新的队尾元素
  QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
  if (!p)
    return ERROR;
  p->next = NULL;
  p->data = e;
  Q.rear->next = p;
  Q.rear = p;
  return OK;
}

Status DeQueue(LinkQueue& Q, int& e)
{
  //若队列不空,则删除Q的队头元素,用e返回其值,并返回OK
  if (Q.front == Q.rear)
    return ERROR;
  QueuePtr p;
  p = Q.front->next;
  e = p->data;
  Q.front->next = p->next;
  if (Q.rear == p)
    Q.rear = Q.front;
  free(p);
  return OK;
}

void createLink() {//创建邻接表
  printf("请输入顶点数n 弧数m:");
  scanf("%d %d", &G->n, &G->m);
  printf("创建的所有点:");
  for (i = 0; i < G->n; i++) { G->adjlist[i].Arc = 0; printf("V%d ", i);     
  for (j = 0; j < G->m; j++) {
    printf("第%d条弧起点编号、终点编号:", j + 1);
    scanf("%d %d", &i, &k);
    ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
    p->ajdVex = k;  //将边所指向的点编号赋值
    p->next = G->adjlist[i].Arc;
    G->adjlist[i].Arc = p;
  }
}

void setFlase() {//visited置零
  hasPath = false;
  for (i = 0; i < G->n; i++) G->visited[i] = false;
}


void existPath(int d, int z) {//两点是否连通
  G->visited[d] = true;
  LinkQueue Q;
  int u;
  int v, w;
  ArcNode* p;
  InitQueue(Q);//置空的辅助队列Q
  //广度优先判断是否存在路径
  for (v = 0; v < G.vexnum; v++)
  {
    if (!visited[v])//v尚未访问
    {
      visited[v] = TRUE;
      printf("%s ", G.vertices[v].data);
      EnQueue(Q, v);//v入队列
      while (!QueueEmpty(Q))
      {

        DeQueue(Q, u);//队头元素出队并置为u
        p = G.vertices[u].firstarc;

        while (p)
        {
          if (!visited[p->adjvex])
          {
            visited[p->adjvex] = TRUE;
            printf("%s ", G.vertices[p->adjvex].data);
            EnQueue(Q, p->adjvex);

          }
          p = p->nextarc;

        }
      }

    }

  }
}


void print_Graph() {//输出邻接表
  ArcNode* p;
  for (i = 0; i < G->n; i++) {
    p = G->adjlist[i].Arc;
    printf("V%d", i);
    while (p) {
      printf("->V%d", p->ajdVex);
      p = p->next;
    }printf("\n");
  }
}

void print_Path(int d, int z) {//输出两点连接路径
  ArcNode* p = G->adjlist[d].Arc;
  printf("路径为:V%d", d);
  while (p) {
    printf("->V%d", p->ajdVex);
    if (p->ajdVex == z)break;
    p = G->adjlist[p->ajdVex].Arc;
  }printf("\n");
}


int main() {
  createLink();
  while (true) {
    printf("\n");
    printf("请输入操作(1.打印信息 2.判断路径 3.退出):");
    int choice; scanf("%d", &choice); setFlase();
    if (choice == 1) print_Graph();
    if (choice == 2) {
      printf("请输入两点编号:"); scanf("%d %d", &i, &k); existPath(i, k);
      if (hasPath) { printf("两点连通!\n"); print_Path(i, k); }
      else printf("两点不连通!\n");
    }
    if (choice == 3)break;
  }
  return 0;
}

测试用例截图:

 运行结果截图

7.3

采用邻接表存储结构,编写一个判别无向图中任意给定的两个顶点之间是否存在一条长度为k的简单路径的算法。

算法思路:在深度优先搜索上经行改进,每走一步就将步长加一,但步长到达k并且该节点和目标结点的值相等时则表示找到了。

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

#define True 1
#define False 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define max_vertex_num 20
#define VertexType char//点类型
#define VRType int //边类型
#define maxsize 20

typedef int Status;
//typedef int bool;

void Visit(VertexType e) {
  printf("%c", e);
}

typedef struct ArcNode {
  int adjV;//边指向的点
  struct ArcNode* next;
}ArcNode;//边

typedef struct VNode {
  VertexType data;
  ArcNode* firstarc;
}VNode,AdjList[max_vertex_num];

typedef struct {
  int vernum, arcnum;
  AdjList vers;
}ALGraph;

Status InitGraph(ALGraph* G) {
  int i;
  G->arcnum = 0;
  G->vernum = 0;
  for (i = 0; i < max_vertex_num; i++)
    G->vers[i].firstarc = NULL;
  return OK;
}

int LocateVex(ALGraph G, VertexType e) {
  //定位元素为e的下标
  int i;
  for (i = 0; i < G.vernum; i++) {
    if (G.vers[i].data == e) {
      return i;
    }
  }
  return -1;
}

Status CreateALG(ALGraph* G) {
  //创建无向图的邻接表
  int i, a, b;
  char tmp[max_vertex_num];
  char h, t;
  ArcNode* p, * q;
  InitGraph(G);
  //printf("顶点数目:");
  scanf("%d", &i);
  G->vernum = i;
  //printf("弧的数目:");
  scanf("%d", &i);
  G->arcnum = i;
  //printf("各顶点信息:");
  scanf("%s", tmp);
  for (i = 0; i < G->vernum; i++)
    G->vers[i].data = tmp[i];
  //printf("请输入弧的信息,两顶点间,隔开");
  for (i = 0; i < G->arcnum; i++)
  {
    scanf("%s", tmp);
    h = tmp[0];
    t = tmp[2];
    a = LocateVex(*G, h);
    b = LocateVex(*G, t);
    if (a < 0 || b < 0)
      return ERROR;
    p = (ArcNode*)malloc(sizeof(ArcNode)); 
    if (!p) exit(OVERFLOW);
    p->adjV = b;
    p->next = NULL;
    if (G->vers[a].firstarc) {
      for (q = G->vers[a].firstarc; q->next; q = q->next);
      q->next = p;
    }
    else {
      G->vers[a].firstarc = p;
    }
    p = (ArcNode*)malloc(sizeof(ArcNode)); 
    if (!p) exit(OVERFLOW);
    p->adjV = a;
    p->next = NULL;
    if(G->vers[b].firstarc){
      for (q = G->vers[b].firstarc; q->next; q = q->next) {
        q->next = p;
      }
    }
    else{
      G->vers[b].firstarc = p;
    
  }

}
  return OK;
}

//判断无向图是否存在路径为k
int visit[max_vertex_num];
int nodenum = 0;
Status ExistPath(ALGraph G, int v, int w, int k) {
  ArcNode* p;
  visit[v] = ++nodenum;
  if (v == w && k == 0)
    return True;
  else if (k > 0) {
    for (p = G.vers[v].firstarc; p; p = p->next) {
      if (visit[p->adjV] == 0) {
        if (ExistPath(G, p->adjV, w, k - 1))
          return True;
        else
          visit[p->adjV] = 0; nodenum--;
      }
      else
        continue;
    }
  }
  return False;
}

int main() {
  int i, j, k;
  int cnt;
  ALGraph G;
  char tmp[20];
  while (1) {
    scanf("%s", tmp); //A-B,1
    i = LocateVex(G, tmp[0]);
    j = LocateVex(G, tmp[2]);
    k = tmp[4] - '0';
    for (cnt = 0; cnt < max_vertex_num; cnt++) visit[cnt] = 0;
    nodenum = 0;
    printf(" %c 到 %c 长度为 %d 的路径:%d", tmp[0], tmp[2], k, ExistPath(G, i, j, k));
    //输出路径
    printf("\t路径是:");
    for (i = 1; i <= k + 1; i++) {
      for (j = 0; j < G.vernum; j++) {
        if (visit[j] == i) {
          Visit(G.vers[j].data);
        }
      }
    }
    printf("\n");
  }
  return 0;
}

测试用例截图:

 7.4

输入任意的一个网,用普里姆(Prim)算法构造最小生成树


#include <stdio.h>
#include <stdlib.h>
#define maxint 32767

typedef struct {
  char vexs[100];
  int arc[100][100];
  int vernum, arcnum;
}AMGraph;

struct {
  char adjvex;
  int lowcost;
}closedge[100];

//已知顶点,获取编号
int LocateVex(AMGraph G, char v) {
  for (int i = 0; i < G.vernum; ++i)
    if (G.vexs[i] == v)
      return i;
  return -1;
}

void CreateUDN(AMGraph& G) {
  int i, j, k;
  printf("输入顶点数和边数(空格隔开)\n");
  scanf("%d %d", &G.vernum, &G.arcnum);
  printf("请输入顶点的值:");
  for (i = 0; i < G.vernum; i++) {
    printf("第%d个顶点数值:", i + 1);
    scanf("%c\n", &G.vexs[i]);
    //printf("\n");
  }
  for (i = 0; i < G.vernum; ++i) {
    for (j = 0; j < G.vernum; ++j) {
      G.arc[i][j] = maxint;//初始化
    }
  }
  printf("\n");
  printf("请输入权值和对应的编号(eg 12 a b)\n");
  for ( k = 0; k < G.arcnum; k++) {
    int weight;
    char v1, v2;
    printf("请输入第%d个:",k + 1);
    scanf("%d %c %c", &weight,&v1,&v2);
    i = LocateVex(G,v1);
    j = LocateVex(G,v2);
    G.arc[i][j] = weight;
    G.arc[j][i] = G.arc[i][j]; 
  }
}

int Min(AMGraph G) {
  int i;
  int index = -1;
  int min = maxint;
  for (i = 0; i < G.vernum; ++i) {
    if (min > closedge[i].lowcost && closedge[i].lowcost != 0) {
      min = closedge[i].lowcost;
      index = i;
    }
    return index;
  }
}

void  prim(AMGraph G, char u) {
  int i, j, k;
  char u0, v0;
  k = LocateVex(G, u);
  for (j = 0; j < G.vernum; ++j) {
    if (j != k) {
      closedge[j].adjvex = u;
      closedge[j].lowcost = G.arc[k][j];
    }
  }
    closedge[k].lowcost = 0;
    for (i = 1; i < G.vernum; ++i) {
      k = Min(G);
      u0 = closedge[k].adjvex;
      v0 = G.vexs[k];
      printf("arc %c --> %c", u0, v0);
      closedge[k].lowcost = 0;
      for (j = 0; j < G.vernum; ++j) {
        if (G.arc[k][j] < closedge[j].lowcost) {
          closedge[j].adjvex = G.vexs[k];
          closedge[j].lowcost = G.arc[k][j];
        }
      }
    }
  }

int main() {
  AMGraph G;
  CreateUDN(G);
  printf("\n");
  prim(G, 'a');//指定顶点a
}

测试用例截图:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1.下列哪一种图的邻接矩阵是对称矩阵?( ) A.有向图 B.无向图 C.AOV网 D.AOE网 2.在边表示活动的AOE网中,关键活动的最迟开始时间( ) 最早开始时间。 A.> B.= D.= 3.带权有向图G用邻接矩阵A存储,则顶点i的入度等于A中( ) 。 A.第i行非∞的元素之和 B.第i列非∞的元素之和 C.第i行非∞且非0的元素个数 D.第i列非∞且非0的元素个数 4.在一个无向图中,所有顶点的度数之和等于所有边数的( ) 倍。 A.1/2 B. 1 C. 2 D. 4 5.对于一个具有n个顶点的无向图,若采用邻接矩阵存储,则该矩阵的大小是(D) A.n B.(n-1)2 C.n-1 D.n2 6. 如下有关拓扑序列的叙述,( ) 不对。 A. 拓扑序列包含了有向图的全部顶点 B. 有向有环图一定没有拓扑序列 C. 有向无环图不一定有拓扑序列 D. 拓扑序列不一定唯一 7. 对于描述工程的AOE网,( ) 说法正确。 A. 网中唯一的出度为零的顶点,称为源点 B. 网中唯一的入度为零的顶点,称为汇点 C. 关键路径是源点到汇点的最短路径 D. 关键路径可能有多条 8. 最小生成树指的是( ) 。 A. 由连通网所得到的边数最少的生成树 B. 由连通网所得到的顶点数相对较少的生成树 C. 连通网中所有生成树中权值之和为最小的成生树 D. 连通网的极小连通子图 9.一个有向图,共有n条弧,则所有顶点的度的总和为( ) 。 A.2n B.n C.n-1 D.n/2 二、填空题(每空3分,共9分)。 1.有n个顶点的连通图至少有___条边。有n个顶点的无向图至多有 条边。 2. 图的广度优先遍历算法中用到辅助队列,每个顶点最多进队 次。 3.在一个具有n个顶点的有向完全图中包含有 条边。 三、综合题(共23分)(答案可以在纸上笔画然后拍照贴图到文档的方式)。 1. (共7分)无向网如下: (1) 给出如图所示网的邻接矩阵表示(3分): (2) 画出最小生成树(4分): 2 .(共8分)已知一个连通图如图所示,试给出图的邻接矩阵和邻接链表存储示意图。 (1) 邻接矩阵存储示意图为(4分): (2) 邻接链表存储示意图为(4分): 3. (共8分)如图所示的带权无向图,请用克鲁斯卡尔算法给出最小生成树的求解过程。 用克鲁斯卡尔算法求最小生成树的过程为:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值