目录
问题 A: 邻接表存储的图转化为邻接矩阵存储的图-附加代码模式
问题 B: 邻接矩阵存储图的DFS-非递归算法(附加代码模式)
问题 D: 邻接矩阵存储图的DFS完成序求解(附加代码模式)
问题 A: 邻接表存储的图转化为邻接矩阵存储的图-附加代码模式
题目描述
邻接表和邻接矩阵,是两种最重要的,也是最基础的图的存储方式。同学们需要熟练掌握这两种方式的程序编写。
以上图为例,其对应的邻接表和邻接矩阵存储方式可以分别表示为:
(1)邻接表法
节点个数:7
节点信息:a b c d e f g
a-g-f
b-c
c-e
d
e-d
f-g-e
g-d
(2)邻接矩阵法
节点个数:7
节点信息:a b c d e f g
0 0 0 0 0 1 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 0 1
0 1 0 1 0 0 0
请编写程序将邻接表法存储的图,转化为邻接矩阵法存储的图,并输出
本题为附加代码模式,以上代码为自动附加在同学们提交的代码后面。在本题的提示中有代码框架,请同学们拷贝后,修改,再注释掉部分代码,最后提交。
输入格式
输入第一行为正整数n(n<100),表示图的节点个数。
接下来n行,表示每个节点的信息,还有以该节点为起点可以到达的其他点的边信息
约定:每个节点信息为小写字母a开始的连续n个字母
输出格式
首先输出邻接表
再输出由0,1组成的邻接矩阵
输入样例
7
a-g-f
b-c
c-e
d
e-d
f-g-e
g-d
输出样例
a --> g --> f
b --> c
c --> e
d
e --> d
f --> g --> e
g --> d
0 0 0 0 0 1 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 0 1
0 0 0 1 0 0 0
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define MAX_SIZE 100
// 邻接矩阵存储的图
struct Graph
{
int vexNumber;
string vexInfo[MAX_SIZE];
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
// 弧结点定义
struct ArcNode
{
char weight; // 弧上的信息部分
int adj; // 邻接点的序号
ArcNode *nextarc; // 下一条边
};
// 顶点结点定义
struct VexNode
{
string Info; // 顶点上的信息部分
ArcNode *firstarc; // 弧链头指针
};
// 邻接表结构的图的定义
struct linkGraph
{
VexNode *vexes; // 每个节点的邻接表
int vexnumber; // 节点数量
};
// 邻接表存储的图的初始化
int InitGraph(linkGraph &G, int vexnumber)
{
G.vexes = new VexNode[vexnumber];
G.vexnumber = vexnumber;
for (int i = 0; i < vexnumber; i++)
G.vexes[i].firstarc = NULL;
return 0;
}
// 构造边节点指针
ArcNode* getArcNode(int adj){
ArcNode* node = new ArcNode();
node->adj = adj;
node->nextarc = nullptr;
return node;
}
// 根据输入构造邻接表存储的图
void InputlinkGraph(linkGraph& LG){
int n;
cin>>n;
InitGraph(LG,n);
for(int i=0;i<n;i++){
string s;
cin>>s;
LG.vexes[i].Info=s[0];
for(int j=1;j<s.size();j++){
if(s[j]=='-')continue;
ArcNode* p= new ArcNode();
ArcNode* a= LG.vexes[i].firstarc;
p->nextarc=NULL;
p->weight=s[j];
p->adj=s[j]-'a';
if(a==NULL)LG.vexes[i].firstarc=p;
else{
while(a->nextarc!=NULL)
a=a->nextarc;
a->nextarc=p;
}
}
}
}
// 将邻接表存储的图转化为邻接矩阵存储的图
void linkGraph2Graph(const linkGraph& LG, Graph& G){
G.vexNumber=LG.vexnumber;
memset(G.adjMatrix,0,sizeof(G.adjMatrix));
for(int i=0;i<LG.vexnumber;i++){
ArcNode* p=LG.vexes[i].firstarc;
while(p!=NULL){
G.adjMatrix[i][p->adj]=1;
p=p->nextarc;
}
}
}
// 输出邻接矩阵
void printGraph(const Graph& G){
for(int i=0;i<G.vexNumber;i++){
for(int j=0;j<G.vexNumber;j++){
cout<<G.adjMatrix[i][j]<<" ";
}
cout<<endl;
}
}
// 输出邻接表
void PrintlinkGraph(const linkGraph& G){
for(int i=0;i<G.vexnumber;i++){
cout<<G.vexes[i].Info;
ArcNode* p=G.vexes[i].firstarc;
while(p!=NULL){
cout<<" --> "<<p->weight;
p=p->nextarc;
}
cout<<endl;
}
}
// 邻接表存储的图的销毁
int DestroylinkGraph(linkGraph &G)
{
for (int i = 0; i < G.vexnumber; i++)
{
while (G.vexes[i].firstarc != NULL)
{
ArcNode *p = G.vexes[i].firstarc;
G.vexes[i].firstarc = p->nextarc;
delete p;
}
}
delete[] G.vexes;
G.vexes = NULL;
G.vexnumber = 0;
return 0;
}
// please comment the following code when you submit to OJ
int main(){
// freopen("/config/workspace/answer/test.in","r",stdin);
linkGraph LG;
Graph G;
InputlinkGraph(LG);
PrintlinkGraph(LG);
linkGraph2Graph(LG,G);
printGraph(G);
DestroylinkGraph(LG);
return 0;
}
问题 B: 邻接矩阵存储图的DFS-非递归算法(附加代码模式)
题目描述
深度优先搜索遍历类似于树的先序遍历,是树的先序遍历算法的推广。
其过程为:假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可以从图中的某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;
若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作为起始点,重复上述过程,直至图中所有顶点都被访问到为止。
在本题中,读入一个图的邻接矩阵(即数组表示),建立图并按照以上描述中的算法遍历所有顶点,输出遍历顶点的顺序。
DFS的非递归算法实现也类似于树的先序遍历算法的非递归实现,用栈来存储节点,如果该节点“完成”了,即所有邻接点都已经被访问,那么该节点将从栈中退出。
本题为附加代码模式,以下代码将自动附加在同学们提交的代码后面。在本题的提示中有代码框架,请同学们拷贝后,修改,再注释掉部分代码,最后提交。
输入格式
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。 以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个0或1,1表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
输出格式
只有一行,包含n个整数,表示按照题目描述中的深度优先遍历算法遍历整个图的访问顶点顺序。每个整数后输出一个空格,并请注意行尾输出换行。
输入样例
4
0 1 0 1
1 0 0 0
0 0 0 1
1 0 1 0
输出样例
0 1 3 2
AC代码:
#include <iostream>
#include <string>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
#define MAX_SIZE 100
// 邻接矩阵存储的图
struct Graph
{
int vexNumber;
string vexInfo[MAX_SIZE];
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
// 查找v0的未被访问的邻接点
// int findAdjVex(const Graph& G, int v0, int visited[]){
// for(int i=0;i<G.vexNumber;i++)
// if(G.adjMatrix[v0][i]==1&&visited[i]==0)return i;
// return 0;
// }
// 以顶点v0为起点,进行一趟DFS
string DFS(const Graph& G, int v0, int visited[]){
string result = "";
result=result+G.vexInfo[v0]+" ";
visited[v0]=1;
for(int i=0;i<G.vexNumber;i++){
if(G.adjMatrix[v0][i]==1&&!visited[i])
result=result+DFS(G,i,visited);
}
return result;
}
// 对整个图进行DFS
string DFS(const Graph& G){
string result = "";
// 第一步:初始化visited数组
int visited[MAX_SIZE]={0};
// 第二步:以每个未被遍历的顶点为起点,进行DFS
for(int i=0;i<G.vexNumber;i++){
if(visited[i]==0){
result+=DFS(G,i,visited);
}
}
return result;
}
// please comment the following code when you submit to OJ
int main(){
// freopen("/config/workspace/answer/test.in","r",stdin);
// freopen("/config/workspace/answer/test.out","w",stdout);
Graph G;
cin >> G.vexNumber;
for(int i=0;i<G.vexNumber;i++){
G.vexInfo[i] = to_string(i);
for(int j=0;j<G.vexNumber;j++){
cin >> G.adjMatrix[i][j];
}
}
string str = DFS(G);
cout << str << endl;
return 0;
}
问题 C: 案例6-1.2:邻接表存储图的广度优先遍历
题目描述
一个图有n个节点编号从0至n-1和m条边编号从0至m-1。 输出从点x开始的广度优先遍历顺序。
输入格式
第一行为n、m、x。
接下来m行每行有一组u,v。表示点u可以到达点v,点v也可以到达点u。
输出格式
输出经过点的顺序。(输出字典序最小的答案)
输入样例
7 9 5
0 3
0 2
0 4
3 1
3 2
4 5
1 5
2 5
5 6
输出样例
5 1 2 4 6 3 0
AC代码:
#include <bits/stdc++.h>
using namespace std;
struct node {
int in, out;
};
int cmp(struct node a, struct node b) {
if (a.in == b.in)
return a.out < b.out;
return a.in < b.in;
}
int main() {
int m, n, x;
cin >> n >> m >> x;
struct node a[m + 5];
for (int i = 0; i < m; i++) {
int j, o;
cin >> j >> o;
if (j < o) {
a[i].in = j;
a[i].out = o;
} else {
a[i].in = o;
a[i].out = j;
}
}
sort(a, a + m, cmp);
queue<int> q;
q.push(x);
int visited[n + 5] = {0};
visited[x] = 1;
while (!q.empty()) {
int p = q.front();
cout << p << " ";
q.pop();
for (int i = 0; i < m; i++) {
if (a[i].in == p && !visited[a[i].out]) {
q.push(a[i].out);
visited[a[i].out] = 1;
} else if (a[i].out == p && !visited[a[i].in]) {
q.push(a[i].in);
visited[a[i].in] = 1;
}
}
}
return 0;
}
问题 D: 邻接矩阵存储图的DFS完成序求解(附加代码模式)
题目描述
在对图进行深度优先遍历的过程中,如果一个节点p没有未被访问的邻接点,则将该节点p标记为“完成”状态。
请编写程序,求解一个图的深度优先遍历完成序。
本题为附加代码模式,以下代码将自动附加在同学们提交的代码后面。在本题的提示中有代码框架,请同学们拷贝后,修改,再注释掉部分代码,最后提交。
输入格式
输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过26。
默认每个顶点对应的信息依次为从a到z的小写字母。
以后的n行中每行有n个用空格隔开的整数0或1,对于第i行的第j个0或1,1表示第i个顶点和第j个顶点有直接连接,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。
默认从a开始dfs,依次顺延
输出格式
只有一行,包含n个字母,表示按照题目描述中的深度优先遍历算法遍历整个图的访问顶点顺序。
输入样例
7
0 0 0 0 0 0 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 0 0 0 1
0 0 0 1 0 0 0
0 0 0 0 1 0 1
0 1 0 0 0 0 0
输出样例
decbgaf
AC代码:
#include <iostream>
#include <string>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
#define MAX_SIZE 100
// 邻接矩阵存储的图
struct Graph
{
int vexNumber;
string vexInfo[MAX_SIZE];
int adjMatrix[MAX_SIZE][MAX_SIZE];
};
// 查找v0的未被访问的邻接点
int findAdjVex(const Graph& G, int v0, int visited[]){
for(int i=0;i<G.vexNumber;i++)
if(G.adjMatrix[v0][i]==1&&!visited[i])return i;
return 0;
}
// 算法7-1: 以某个节点为起点求解DFS完成序的算法 (邻接矩阵)
string DFS_finished(const Graph &G, int v0, int visited[]){
string result="";
visited[v0]=1;
for(int i=0;i<G.vexNumber;i++){
if(G.adjMatrix[v0][i]==1&&!visited[i])
result+=DFS_finished(G,i,visited);
}
result=result+G.vexInfo[v0];
return result;
}
// 算法7: DFS完成序的求解算法-邻接矩阵
string DFS_finished(const Graph &G){
string result="";
int visited[MAX_SIZE]={0};
for(int i=0;i<G.vexNumber;i++){
if(visited[i]==0)result+=DFS_finished(G,i,visited);
}
return result;
}
// please comment the following code when you submit to OJ
int main(){
// freopen("/config/workspace/answer/test.in","r",stdin);
// freopen("/config/workspace/answer/test.out","w",stdout);
Graph G;
cin >> G.vexNumber;
for(int i=0;i<G.vexNumber;i++){
G.vexInfo[i] = (char)('a'+ i);
for(int j=0;j<G.vexNumber;j++){
cin >> G.adjMatrix[i][j];
}
}
string str = DFS_finished(G);
cout << str << endl;
return 0;
}
问题 E: 基础实验6-2.3:拯救007
题目描述
在老电影“007之生死关头”(Live and Let Die)中有一个情节,007被毒贩抓到一个鳄鱼池中心的小岛上,他用了一种极为大胆的方法逃脱 —— 直接踩着池子里一系列鳄鱼的大脑袋跳上岸去!(据说当年替身演员被最后一条鳄鱼咬住了脚,幸好穿的是特别加厚的靴子才逃过一劫。)
设鳄鱼池是长宽为100米的方形,中心坐标为 (0, 0),且东北角坐标为 (50, 50)。池心岛是以 (0, 0) 为圆心、直径15米的圆。给定池中分布的鳄鱼的坐标、以及007一次能跳跃的最大距离,你需要告诉他是否有可能逃出生天。
输入格式
首先第一行给出两个正整数:鳄鱼数量 N(≤100)和007一次能跳跃的最大距离 D 。随后 N 行,每行给出两个整数,代表一条鳄鱼的 (x,y ) 坐标。
注意:不会有两条鳄鱼待在同一个点上。
输出格式
如果007有可能逃脱,就在一行中输出"Yes",否则输出"No"。
输入样例
14 20
25 -15
-25 28
8 49
29 15
-35 -2
5 28
27 -29
-8 -28
-20 -35
-25 -20
-13 29
-30 15
-35 40
12 12
输出样例
Yes
AC代码:
#include <bits/stdc++.h>
using namespace std;
struct Point{
int x,y;
};
typedef Point Point;
int CanSafe(Point c[],int v,int D){
if(c[v].x+D>=50||c[v].x-D>=50||c[v].y-D>=50||c[v].y+D>=50)return 1;
return 0;
}
int CanJump(Point c[],int v,int u,int D){
if((c[v].x-c[u].x)*(c[v].x-c[u].x)+(c[v].y-c[u].y)*(c[v].y-c[u].y)<=D*D)return 1;
return 0;
}
int CanFirst(Point c[],int v,int D){
if(c[v].x*c[v].x+c[v].y*c[v].y<=(D+7.5)*(D+7.5))return 1;
return 0;
}
int DFS(int N,int D,Point c[],int v,int visited[]){
visited[v]=1;
if(CanSafe(c,v,D))return 1;
for(int i=0;i<N;i++){
if(visited[i]==0&&CanJump(c,v,i,D)){
if(DFS(N,D,c,i,visited)==1)return 1;
}
}
return 0;
}
int DFS(int N,int D,Point c[]){
int visited[N]={0};
for(int i=0;i<N;i++){
if(CanFirst(c,i,D)&&visited[i]==0){
visited[i]=1;
if(1==DFS(N,D,c,i,visited))return 1;
}
}
return 0;
}
int main(){
int N,D;
cin>>N>>D;
Point c[N];
for(int i=0;i<N;i++)cin>>c[i].x>>c[i].y;
int result=DFS(N,D,c);
if(result==1)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
感谢ly老师在课上给出了好多代码 ,虽然有小小的bug,但可以直接抄了使写题思路更加清晰了🥹🥹🥹
感谢江某某宝贵的出差机会🥹🥹🥹