数据结构——浙大版中国大学mooc(week6)

本文探讨了浙大版中国大学MOOC中关于图的课程内容,包括使用DFS和BFS列出无向图的连通集,以及解决James Bond电影场景中的逃脱问题。在连通集问题中,需要基于邻接矩阵或邻接表建立图并进行深度优先和广度优先搜索。在第二个问题中,介绍了如何判断James Bond能否通过设定的跳跃距离逃离鳄鱼湖。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

课程给出代码

C语言:图的邻接矩阵实现建立

/* 图的邻接矩阵表示法 */
 
#define MaxVertexNum 100    /* 最大顶点数设为100 */
#define INFINITY 65535        /* ∞设为双字节无符号整数的最大值65535*/
typedef int Vertex;         /* 用顶点下标表示顶点,为整型 */
typedef int WeightType;        /* 边的权值设为整型 */
typedef char DataType;        /* 顶点存储的数据类型设为字符型 */
 
/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;      /* 有向边<V1, V2> */
    WeightType Weight;  /* 权重 */
};
typedef PtrToENode Edge;
        
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 顶点数 */
    int Ne;  /* 边数   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
    DataType Data[MaxVertexNum];      /* 存顶点的数据 */
    /* 注意:很多情况下,顶点无数据,此时Data[]可以不用出现 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
 
 
 
MGraph CreateGraph( int VertexNum )
{ /* 初始化一个有VertexNum个顶点但没有边的图 */
    Vertex V, W;
    MGraph Graph;
     
    Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立图 */
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    /* 初始化邻接矩阵 */
    /* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
    for (V=0; V<Graph->Nv; V++)
        for (W=0; W<Graph->Nv; W++)  
            Graph->G[V][W] = INFINITY;
             
    return Graph; 
}
        
void InsertEdge( MGraph Graph, Edge E )
{
     /* 插入边 <V1, V2> */
     Graph->G[E->V1][E->V2] = E->Weight;    
     /* 若是无向图,还要插入边<V2, V1> */
     Graph->G[E->V2][E->V1] = E->Weight;
}
 
MGraph BuildGraph()
{
    MGraph Graph;
    Edge E;
    Vertex V;
    int Nv, i;
     
    scanf("%d", &Nv);   /* 读入顶点个数 */
    Graph = CreateGraph(Nv); /* 初始化有Nv个顶点但没有边的图 */ 
     
    scanf("%d", &(Graph->Ne));   /* 读入边数 */
    if ( Graph->Ne != 0 ) { /* 如果有边 */ 
        E = (Edge)malloc(sizeof(struct ENode)); /* 建立边结点 */ 
        /* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
        for (i=0; i<Graph->Ne; i++) {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); 
            /* 注意:如果权重不是整型,Weight的读入格式要改 */
            InsertEdge( Graph, E );
        }
    } 
 
    /* 如果顶点有数据的话,读入数据 */
    for (V=0; V<Graph->Nv; V++) 
        scanf(" %c", &(Graph->Data[V]));
 
    return Graph;
}

C语言:图的邻接表实现建立

/* 图的邻接表表示法 */
 
#define MaxVertexNum 100    /* 最大顶点数设为100 */
typedef int Vertex;         /* 用顶点下标表示顶点,为整型 */
typedef int WeightType;        /* 边的权值设为整型 */
typedef char DataType;        /* 顶点存储的数据类型设为字符型 */
 
/* 边的定义 */
typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;      /* 有向边<V1, V2> */
    WeightType Weight;  /* 权重 */
};
typedef PtrToENode Edge;
 
/* 邻接点的定义 */
typedef struct AdjVNode *PtrToAdjVNode; 
struct AdjVNode{
    Vertex AdjV;        /* 邻接点下标 */
    WeightType Weight;  /* 边权重 */
    PtrToAdjVNode Next;    /* 指向下一个邻接点的指针 */
};
 
/* 顶点表头结点的定义 */
typedef struct Vnode{
    PtrToAdjVNode FirstEdge;/* 边表头指针 */
    DataType Data;            /* 存顶点的数据 */
    /* 注意:很多情况下,顶点无数据,此时Data可以不用出现 */
} AdjList[MaxVertexNum];    /* AdjList是邻接表类型 */
 
/* 图结点的定义 */
typedef struct GNode *PtrToGNode;
struct GNode{  
    int Nv;     /* 顶点数 */
    int Ne;     /* 边数   */
    AdjList G;  /* 邻接表 */
};
typedef PtrToGNode LGraph; /* 以邻接表方式存储的图类型 */
 
 
 
LGraph CreateGraph( int VertexNum )
{ /* 初始化一个有VertexNum个顶点但没有边的图 */
    Vertex V;
    LGraph Graph;
     
    Graph = (LGraph)malloc( sizeof(struct GNode) ); /* 建立图 */
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    /* 初始化邻接表头指针 */
    /* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */
       for (V=0; V<Graph->Nv; V++)
        Graph->G[V].FirstEdge = NULL;
             
    return Graph; 
}
        
void InsertEdge( LGraph Graph, Edge E )
{
    PtrToAdjVNode NewNode;
     
    /* 插入边 <V1, V2> */
    /* 为V2建立新的邻接点 */
    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V2;
    NewNode->Weight = E->Weight;
    /* 将V2插入V1的表头 */
    NewNode->Next = Graph->G[E->V1].FirstEdge;
    Graph->G[E->V1].FirstEdge = NewNode;
         
    /* 若是无向图,还要插入边 <V2, V1> */
    /* 为V1建立新的邻接点 */
    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V1;
    NewNode->Weight = E->Weight;
    /* 将V1插入V2的表头 */
    NewNode->Next = Graph->G[E->V2].FirstEdge;
    Graph->G[E->V2].FirstEdge = NewNode;
}
 
LGraph BuildGraph()
{
    LGraph Graph;
    Edge E;
    Vertex V;
    int Nv, i;
     
    scanf("%d", &Nv);   /* 读入顶点个数 */
    Graph = CreateGraph(Nv); /* 初始化有Nv个顶点但没有边的图 */ 
     
    scanf("%d", &(Graph->Ne));   /* 读入边数 */
    if ( Graph->Ne != 0 ) { /* 如果有边 */ 
        E = (Edge)malloc( sizeof(struct ENode) ); /* 建立边结点 */ 
        /* 读入边,格式为"起点 终点 权重",插入邻接矩阵 */
        for (i=0; i<Graph->Ne; i++) {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); 
            /* 注意:如果权重不是整型,Weight的读入格式要改 */
            InsertEdge( Graph, E );
        }
    } 
 
    /* 如果顶点有数据的话,读入数据 */
    for (V=0; V<Graph->Nv; V++) 
        scanf(" %c", &(Graph->G[V].Data));
 
    return Graph;
}

C语言:图的存储

/* 邻接表存储的图 - DFS */
 
void Visit( Vertex V )
{
    printf("正在访问顶点%d\n", V);
}
 
/* Visited[]为全局变量,已经初始化为false */
void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) )
{   /* 以V为出发点对邻接表存储的图Graph进行DFS搜索 */
    PtrToAdjVNode W;
     
    Visit( V ); /* 访问第V个顶点 */
    Visited[V] = true; /* 标记V已访问 */
 
    for( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 对V的每个邻接点W->AdjV */
        if ( !Visited[W->AdjV] )    /* 若W->AdjV未被访问 */
            DFS( Graph, W->AdjV, Visit );    /* 则递归访问之 */
}


/* 邻接矩阵存储的图 - BFS */
 
/* IsEdge(Graph, V, W)检查<V, W>是否图Graph中的一条边,即W是否V的邻接点。  */
/* 此函数根据图的不同类型要做不同的实现,关键取决于对不存在的边的表示方法。*/
/* 例如对有权图, 如果不存在的边被初始化为INFINITY, 则函数实现如下:         */
bool IsEdge( MGraph Graph, Vertex V, Vertex W )
{
    return Graph->G[V][W]<INFINITY ? true : false;
}
 
/* Visited[]为全局变量,已经初始化为false */
void BFS ( MGraph Graph, Vertex S, void (*Visit)(Vertex) )
{   /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
    Queue Q;     
    Vertex V, W;
 
    Q = CreateQueue( MaxSize ); /* 创建空队列, MaxSize为外部定义的常数 */
    /* 访问顶点S:此处可根据具体访问需要改写 */
    Visit( S );
    Visited[S] = true; /* 标记S已访问 */
    AddQ(Q, S); /* S入队列 */
     
    while ( !IsEmpty(Q) ) {
        V = DeleteQ(Q);  /* 弹出V */
        for( W=0; W<Graph->Nv; W++ ) /* 对图中的每个顶点W */
            /* 若W是V的邻接点并且未访问过 */
            if ( !Visited[W] && IsEdge(Graph, V, W) ) {
                /* 访问顶点W */
                Visit( W );
                Visited[W] = true; /* 标记W已访问 */
                AddQ(Q, W); /* W入队列 */
            }
    } /* while结束*/
}

06-图1 列出连通集 (25 分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。
输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。
输出格式:
按照"{ v​1 v​2 … v​k }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

#include<stdio.h>
#include<stdlib.h>
 
#define MAXN 10
int visited[MAXN] = {0};
 
//建立邻接矩阵 //Create Graph
int G[MAXN][MAXN]={0},NV,NE;
 
void BuildGraph(){
	int i,j,v1,v2;
	scanf("%d%d",&NV,&NE);
	for( i=0; i<NE; i++){
		scanf("%d%d",&v1,&v2);               //InsertEdge
		G[v1][v2] = 1;
		G[v2][v1] = 1;
	}
}
//DFS
void DFS(int v)
{
	visited[v] = 1;
	printf("%d ",v);                        //输出这个点 
	for(int i=0; i<NV; i++){
		if(G[v][i] && !visited[i]){         //如果联通这个点且没有访问过 
			DFS(i);
		}
	}
} 
 
void ListComponentsDFS(){
	int i;	
	for(i=0; i<NV; i++){
		if(!visited[i]){ 
			printf("{ "); 
			DFS(i);
			printf("}\n");
		}
	}
}
//初始化visited
void isvisited(){
	for(int i=0; i<MAXN; i++){
		visited[i] = 0;
	}
}  
//BFS
void BFS(int v){
	const int MAXSIZE=100;                 //队列
	int quene[MAXSIZE];
	int first = -1, rear = -1; 
	quene[++rear] = v;//入队 
	visited[v] = 1;
	while(first < rear){                   //队列不为空
		int de = quene[++first];           //出队
		printf("%d ",de);
		for(int i=0; i<NV; i++){
			if(!visited[i]&&G[de][i]){
				visited[i] = 1;
				quene[++rear] = i;
			}
		} 
	} 
}
 
 
void ListComponentsBFS(){
	int i;	
	for(i=0; i<NV; i++){
		if(!visited[i]){
			printf("{ "); 
			BFS(i);
			printf("}\n");
		}
	}
}
 
int main(){
	BuildGraph();                     //建图
	ListComponentsDFS();              //DFS遍历连通集
	isvisited();                      //BFS遍历连通集 
	ListComponentsBFS();	
	return 0;
}

06-图2 Saving James Bond - Easy Version (25 分)

This time let us consider the situation in the movie “Live and Let Die” in which James Bond, the world’s most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape – he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head… Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).
Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.
Input Specification:
Each input file contains one test case. Each case starts with a line containing two positive integers N (≤100), the number of crocodiles, and D, the maximum distance that James could jump. Then N lines follow, each containing the (x,y) location of a crocodile. Note that no two crocodiles are staying at the same position.
Output Specification:
For each test case, print in a line “Yes” if James can escape, or “No” if not.

#include<stdio.h>
#include <math.h>
#include<stdbool.h>

int n, m;
#define MINLEN 42.5

struct Pointer {
    int x;
    int y;
}p[101];

bool answer = false;           /* 记录007能否安全逃生~~ */
bool visited[101] = {false};   /* 判断当前点是否被访问过 */

bool isSave(int x) {           /* 判断从当前点能否跳到岸上 */
    if ((p[x].x - m <= -50) || (p[x].x + m >= 50) || (p[x].y - m <= -50) || (p[x].y + m >= 50))
        return true;
    return false;
}

bool jump(int x, int y) {       /* 判断2个点距离是否在跳跃能力内 */
        int p1 = pow(p[x].x - p[y].x, 2);
        int p2 = pow(p[x].y - p[y].y, 2);
        int r = m * m;
        if (p1 + p2 <= r)
            return true;
        return false;
}

bool firstJump(int x) {         /* 第一次可以选择跳的鳄鱼由于小岛半径的原因算法不同单独判断 */
    int p1 = pow(p[x].x , 2);
    int p2 = pow(p[x].y , 2);
    int r = (m+7.5) * (m+7.5);
    if (p1 + p2 <= r){
        return true;
    }
    return false;
}
bool dfs(int x) {               /* DFS */
    visited[x] = true;
    if (isSave(x)) {
        answer = true;
    }
    for (int i = 0; i < n; i++) {
        if (!visited[i] && jump(x, i)){ /* 没访问过且在可跳 */
            answer = dfs(i);
            if (answer == true)
                break;
        }
    }
    return answer;
}

int main() {
	scanf("%d %d",&n,&m);
    for (int i = 0; i < n; i++) {
		scanf("%d %d",&p[i].x,&p[i].y);
    }
    if (m >= MINLEN) {                   /* 节点可上岸 */
        printf("Yes\n");
        return 0;
    }
    for (int i = 0; i < n; i++) {
        if (firstJump(i) && !visited[i]) { /* 如果第一次能够跳的 并且之前没有访问过的节点 则深搜该节点 */
            if (dfs(i))
                break;
        }
    }
    if (answer == true)
        printf("Yes\n");
    else
        printf("No\n");
    return 0;
}

06-图3 六度空间 (30 分)

这题没时间做了参照,博客https://blog.youkuaiyun.com/qq_36589706/article/details/84334446
在这里插入图片描述

#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
int const maxn=10000;
int N, M;
int visit[maxn];
int arr[maxn][maxn];
int BFS(int v){
	queue<int> q;
	int temp, level=0, tail, last=v, count=1;
	q.push(v);
	visit[v]=1;
	while(!q.empty()){
		temp=q.front();
		q.pop();
		for(int i=1; i<=N; i++){
			if(arr[temp][i]&&visit[i]==0){
				count++;
				tail=i;
				visit[i]=1;
				q.push(i);
			}
		}
		if(temp==last){
			level++;
			last=tail;
		}
		if(level==6)break;
	}
	return count;
}
int main(){
	scanf("%d%d", &N, &M);
	int a, b;
	for(int i=0; i<M; i++){
		scanf("%d%d", &a, &b);
		arr[a][b]=1;
		arr[b][a]=1;
	}
	for(int i=1; i<=N; i++){
		int cnt=BFS(i);
		memset(visit, 0, sizeof(visit));
		double f=100.00*cnt/N;
		printf("%d: %.02f%%\n", i, f);
	}
 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值