【数据结构初学笔记17】第六章图(上)MOOC练习题

课后习题:

  1.   列出连通集 非常基础的训练,一定要做;

  2.  Saving James Bond - Easy Version 可怜的007在等着你拯救,你……看着办哈;

  3.  六度空间 在听完课以后,这题的思路应该比较清晰了,不过实现起来还是颇有码量的,有时间就尝试一下。

1.列出连通集

注意:第一个采用的邻接矩阵方法,第二个采用的邻接表方法,使用邻接表的输出结果不满足题目要求。

/*题意理解:列出连通集,先输出DFS,在输出BFS*/
/*思路:1先采用邻接矩阵的存储方法试一下*/
/*邻接矩阵存储实现*/

/*----邻接矩阵中,广度优先搜索BFS设计思路:
1,首先定义全局变量bool Visited[],储存每个顶点V的访问标记,并初始化为false
2,创建空队,将顶点下标入队;
3,如果队非空,出队一个元素X,逐个检查所有顶点是否为邻接点;若顶点Y为邻接点(Graph->G[X][Y]=1),且未被访问过,访问Y并标记Y,将顶点Y入队
4,步骤3循环执行,直至队列空。*/

/*----邻接矩阵中,深度优先搜索DFS设计思路:(自己补充)
1,首先定义全局变量bool Visited[],储存每个顶点V的访问标记,并初始化为false;
2,首先将顶点V标记为已访问,接下来逐个检查所有顶点是否为S的邻接点;
3,若顶点W为邻接点(Graph->G[X][Y]=1),且未被访问过,递归调用DFS(Graph,Y,visit)
3,递归结束,继续判断顶点S的下一个邻接点W++;
*/

/*邻接矩阵表示思路:
1,定义边对应的结构体ENode,其中存储有向边<Vq1,V2>,和该边的权重;
2,定义图结点对应的结构体GNode,其中存储顶点数Nv,边数Ne,邻接矩阵G[预设值][预设值](用邻接矩阵的顶点下标表示顶点)(矩阵元素对应每个单向边的权重),以及每个顶点的数据(比如边的名字)
3,初始化图:一个具有N个顶点,但无边的图,要申请图结点空间GNode,初始化其中各项值
4,插入边:将边结构体ENode其中的单向边值和权重值传入图结点GNode;
5,建立图:读入顶点数,初始化一个空图,读入所有边数据存入邻接矩阵中,读入每个结点的数据存入Data;
*/

/*注意&必读:
1,这里默认顶点编号从0开始,到(Graph->Nv - 1) ,所以你在用的时候要额外注意输入的顶点从0还是从1开始
*/

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

/*队列的矩阵存储实现*/
#define ElementType int
#define MaxSize 100
typedef struct QNode *Queue;
struct QNode
{
    ElementType Data[MaxSize];
    int rear;  //记录尾元素序号
    int front; //记录头元素序号
};

/*图的邻接矩阵表示方法*/
#define MaxVertexNum 100 /*最大顶点数*/
#define INFINITY 65535   /*无穷设为双字节无符号整数的最大值65535*/

bool Visited[MaxVertexNum] = {false}; //结点是否被访问过的标志

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个顶点但没有边的图 */
void InsertEdge(MGraph Graph, Edge E);                   /*插入边,边权重值默认为1*/
MGraph BuildGraph();                                     /*根据输入,建立一个图*/
bool IsEdge(MGraph Graph, Vertex V, Vertex W);           /*判断两个顶点之间是否有边存在*/
void Visit(Vertex V);                                    /*访问结点*/
void BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex)); /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
void DFS(MGraph Graph, Vertex S, void (*Visit)(Vertex)); /* 以S为出发点对邻接矩阵存储的图Graph进行DFS搜索 */

void AddQ(Queue PtrQ, ElementType item); //入队列,队列采用循环结构可以最大限度利用空间
ElementType DeleteQ(Queue PtrQ);         //出队列
int IsEmpty(Queue PtrQ);                 /*队列空,返回1*/
Queue CreateQueue();                     /*创建空队*/

int main(void)
{
    int i, j;
    MGraph G;
    G = BuildGraph();
    for (i = 0; i < G->Nv; i++) /*广度优先搜索并打印连通集*/
    {
        if (Visited[i] != true)
        {
            printf("{");
            DFS(G, i, Visit);
            printf(" }\n");
        }
    }
    for ( i = 0; i < G->Nv; i++)
    {/*清除访问标志Visited[]*/
        Visited[i] = false;
    }   
    for (i = 0; i < G->Nv; i++) /*深度优先搜索并打印连通集*/
    {
        if (Visited[i] != true)
        {
            printf("{");
            BFS(G, i, Visit);
            printf(" }\n");
        }
    }
    return 0;
}

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] = 0; /*空权重全部为0*/
            Graph->G[V][W] = INFINITY;

    return Graph;
}

void InsertEdge(MGraph Graph, Edge E)
{ /*权重值默认为1*/
    /* 插入边 <V1, V2> */
    Graph->G[E->V1][E->V2] = 1;
    /* 若是无向图,还要插入边<V2, V1> */
    Graph->G[E->V2][E->V1] = 1;
}

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", &E->V1, &E->V2);
            /* 注意:如果权重不是整型,Weight的读入格式要改 */
            InsertEdge(Graph, E);
        }
    }
    // /* 如果顶点有数据的话,读入数据 */
    // for (V = 0; V < Graph->Nv; V++)
    //     scanf(" %c", &(Graph->Data[V]));
    return Graph;
}

/* 深度优先搜索实现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;
}

void Visit(Vertex V)
{
    printf(" %d", V);
}
/* Visited[]为全局变量,已经初始化为false */
void BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex))
{ /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
    Queue Q;
    Vertex V, W;

    Q = CreateQueue(); /* 创建空队列, 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结束*/
}
/* Visited[]为全局变量,已经初始化为false */
void DFS(MGraph Graph, Vertex S, void (*Visit)(Vertex))
{ /* 以S为出发点对邻接矩阵存储的图Graph进行DFS搜索 */
    Vertex W;
    /*访问顶点S:此处可以根据具体访问需要改写*/
    Visit(S);
    Visited[S] = true;              /*标记S已访问*/
    for (W = 0; W < Graph->Nv; W++) /*对图中的每个顶点W*/
    {                               /*若W是S的邻接点且未被访问过*/
        if (!Visited[W] && IsEdge(Graph, S, W))
        {
            DFS(Graph, W, Visit);
        }
    }
}

// 04.创建空队
Queue CreateQueue()
{
    Queue Q;
    Q = (Queue)malloc(sizeof(struct QNode));
    Q->front = 0;
    Q->rear = MaxSize;
    return Q;
}
// 02.入队列,队列采用循环结构可以最大限度利用空间
void AddQ(Queue PtrQ, ElementType item)
{
    if ((PtrQ->rear + 1) % MaxSize == PtrQ->front)
    {
        printf("队列满");
        return;
    }
    PtrQ->rear = (PtrQ->rear + 1) % MaxSize;
    PtrQ->Data[PtrQ->rear] = item;
}
// 03.出队列
ElementType DeleteQ(Queue PtrQ)
{
    ElementType item;
    if (PtrQ->front == PtrQ->rear)
    {
        printf("队列空");
        return 0;
    }
    PtrQ->front = (PtrQ->front + 1) % MaxSize;
    return (PtrQ->Data[PtrQ->front]);
}
//判断是否空
int IsEmpty(Queue PtrQ)
{
    if (PtrQ->front == PtrQ->rear)
    {
        // printf("队列空");
        return 1;
    }
    else
        return 0;
}

/*输入样例
8 6
0 7
0 1
2 0
4 1
2 4
3 5
*/
/*输出样例
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }
*/
/*题意理解:列出连通集,先输出DFS,在输出BFS;要使用邻接矩阵格式,因为要求:进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。*/
/*思路:2用邻接表的存储方法试一下,不满足输出顺序的要求*/
/*邻接表存储实现*/

/*----邻接表中,深度优先搜索DFS实现思路
1,首先定义全局变量bool Visited[],储存每个顶点V的访问标记,并初始化为false
2,首先将顶点V标记为已访问;若邻接点指针W(W=Graph->G[V].FirstEdge)不为空,判断邻接点是否被访问过;
3,若未被访问过,则递归调用DFS(Graph,W-AdjV,Visit);
4,递归结束,继续判断顶点V的下一个邻接点W=W->Next;*/

/*----邻接表中,广度优先搜索BFS实现思路(自己补充)
1,首先定义全局变量bool Visited[],储存每个顶点V的访问标记,并初始化为false
2,创建空队,访问顶点下标S,并将顶点下标S入队;
3,如果队非空,出队一个顶点下标X;若顶点下标X存在邻接点指针Y(Y=Graph->G[X].FirstEdge!=NULL)且未被访问过,访问并标记Y,将顶点Y->AdjV入队;
4,如此检查顶点X的所有邻接点(Y=Y->Next);
5,步骤3,4循环执行,直至队列空。*/

/*图的邻接表思路
1,定义一个边的结构体ENode,存储有向边<Vq1,V2>,和该边的权重Weight;
2,图结点通过定义结构体GNode,存储顶点数Nv,边数Ne和邻接表G;
2,邻接表G是一个指针数组,其中每一个指针都指向一个顶点表头结点Vnode;
2,顶点表头结点Vnode存储了一个边表头指针FirstEdge,和该位置顶点的数据
2,FirstEdge是一个邻接点类型的结构体指针,邻接点结构体包含了邻接点的下标AdjV,顶点与邻接点的边权重,和下一个邻接点指针变量。
3,初始化一个空图:对图结点申请空间,初始化顶点数Nv,边数Ne和邻接表G中指针为NULL;
4,插入边:根据输入数据建立一个边结点结构体ENode,创建邻接点结构体AdjVNode并申请空间,对其下标、权重进行赋值,将Graph->G[E->V2].FirstEdge链接在AdjVNode->Next中,并将AdjVNode指针存放在Graph->G[E->V2].FirstEdge中;
5,建立图:读入顶点个数,并初始化空图;逐个读入每一条边,存入边结构体ENode,并插入图Graph中;若有顶点数据,将其存入Graph->G[i].Data中。
*/

/*注意&必读:
1,这里默认顶点编号从0开始,到(Graph->Nv - 1) ,所以你在用的时候要额外注意输入的顶点从0还是从1开始
*/

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

#define ElementType int
#define MaxSize 100
typedef struct QNode *Queue;
struct QNode
{
    ElementType Data[MaxSize];
    int rear;  //记录尾元素序号
    int front; //记录头元素序号
};

/* 图的邻接表表示法 */
#define MaxVertexNum 100 /* 最大顶点数设为100 */
typedef int Vertex;      /* 用顶点下标表示顶点,为整型 */
typedef int WeightType;  /* 边的权值设为整型 */
typedef char DataType;   /* 顶点存储的数据类型设为字符型 */

bool Visited[MaxVertexNum] = {false}; //结点是否被访问过的标志

/* 边的定义 */
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个顶点但没有边的图 */
void InsertEdge(LGraph Graph, Edge E); /*向图中插入一条边*/
LGraph BuildGraph();                   /*根据输入,建立图*/
void Visit(Vertex V);
void DFS(LGraph Graph, Vertex V, void (*Visit)(Vertex)); /* 以V为出发点对邻接表存储的图Graph进行DFS搜索 */
void BFS(LGraph Graph, Vertex S, void (*Visit)(Vertex)); /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */

void AddQ(Queue PtrQ, ElementType item); //入队列,队列采用循环结构可以最大限度利用空间
ElementType DeleteQ(Queue PtrQ);         //出队列
int IsEmpty(Queue PtrQ);                 /*队列空,返回1*/
Queue CreateQueue();                     /*创建空队*/

int main(void)
{
    int i;
    LGraph G;
    G = BuildGraph();
    for (i = 0; i < G->Nv; i++)
    {
        if (Visited[i] != true)
        {
            printf("{");
            DFS(G, i, Visit);
            printf(" }\n");
        }
    }
    for (i = 0; i < G->Nv; i++)
    { /*清除访问标志Visited[]*/
        Visited[i] = false;
    }
    for (i = 0; i < G->Nv; i++) /*深度优先搜索并打印连通集*/
    {
        if (Visited[i] != true)
        {
            printf("{");
            BFS(G, i, Visit);
            printf(" }\n");
        }
    }
    return 0;
}

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 = 1; /*将边的权重设为默认值*/
    /* 将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", &E->V1, &E->V2);
            /* 注意:如果权重不是整型,Weight的读入格式要改 */
            InsertEdge(Graph, E);
        }
    }

    // /* 如果顶点有数据的话,读入数据 */
    // for (V=0; V<Graph->Nv; V++)
    //     scanf(" %c", &(Graph->G[V].Data));

    return Graph;
}

/* 邻接表存储的图 - DFS&BFS(自己实现,可能有错误) */
void Visit(Vertex V)
{
    printf(" %d", 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);             /* 则递归访问之 */
}

/* Visited[]为全局变量,已经初始化为false */
void BFS(LGraph Graph, Vertex S, void (*Visit)(Vertex))
{ /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
    Queue Q;
    Vertex V;        //顶点下标V
    PtrToAdjVNode W; //邻接点指针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 = Graph->G[V].FirstEdge; W; W = W->Next) /* 对顶点V的每一个邻接点*/
            /* 若邻接点W并且未访问过 */
            if (!Visited[W->AdjV])
            {
                /* 访问顶点W */
                Visit(W->AdjV);
                Visited[W->AdjV] = true; /* 标记W已访问 */
                AddQ(Q, W->AdjV);        /* W入队列 */
            }
    } /* while结束*/
}

// 04.创建空队
Queue CreateQueue()
{
    Queue Q;
    Q = (Queue)malloc(sizeof(struct QNode));
    Q->front = 0;
    Q->rear = MaxSize;
    return Q;
}
// 02.入队列,队列采用循环结构可以最大限度利用空间
void AddQ(Queue PtrQ, ElementType item)
{
    if ((PtrQ->rear + 1) % MaxSize == PtrQ->front)
    {
        printf("队列满");
        return;
    }
    PtrQ->rear = (PtrQ->rear + 1) % MaxSize;
    PtrQ->Data[PtrQ->rear] = item;
}
// 03.出队列
ElementType DeleteQ(Queue PtrQ)
{
    ElementType item;
    if (PtrQ->front == PtrQ->rear)
    {
        printf("队列空");
        return 0;
    }
    PtrQ->front = (PtrQ->front + 1) % MaxSize;
    return (PtrQ->Data[PtrQ->front]);
}
//判断是否空
int IsEmpty(Queue PtrQ)
{
    if (PtrQ->front == PtrQ->rear)
    {
        // printf("队列空");
        return 1;
    }
    else
        return 0;
}

2.Saving James Bond - Easy Version

注意:拯救007,非常有意思的一道题,主要

/*题目分析:湖的大小100*100,007在岛的中心,岛半径15,每次能跳D距离远,第一行输入鳄鱼个数N和距离D,若能上岸打印'Yes',否则'No'*/
/*思路分析:
1,Crocs矩阵存储鳄鱼坐标(0-100),Coast矩阵存储能否上岸,默认值为0;
2,第一步搜索007从小岛能跳到的所有鳄鱼坐标,第二步使用DFS逐个搜索这些坐标。
3,DFS要先判断点能否上岸,若不能继续查找距离小于D的未被访问过的鳄鱼。
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#define Maxsize 100
#define ElementType int
typedef struct Graph *PtrGraph;
bool Visited[Maxsize][Maxsize] = {false}; //结点是否被访问过的标志
struct Graph
{
    ElementType Crocs[Maxsize][Maxsize]; //存鳄鱼的位置坐标,1表示有鳄鱼
    bool Up[Maxsize][Maxsize];           //存该点能否上岸,1表示能上岸
    int V;                               //顶点数
};

void Insert(int x1, int y1, int D, PtrGraph PtrG); //将鳄鱼坐标插入坐标图,并计算该点能否上岸。
int DFS(PtrGraph PtrG, int x1, int y1, int D);     //深度优先搜索
int IsNear(int x1, int y1, int x2, int y2, int D); //判断能否调到,能挑到返回1
void pause(void);                                  //暂停函数,方便调试
int main(void)
{
    struct Graph G = {0, false}; //初始化结构体G
    PtrGraph PtrG = &G;
    int N, D, i, j, x1, y1, count, mark;
    mark = 0;
    scanf("%d%d", &N, &D);
    for (i = 0; i < N; i++)
    {
        scanf("%d%d", &x1, &y1); //横纵坐标范围(-50,50)
        Insert(x1, y1, D, PtrG); //将鳄鱼坐标插入坐标图,并计算该点能否上岸。
    }
    for (i = 0; i < 100; i++)
    {
        for (j = 0; j < 100; j++)
        { //查找007在岛上能跳到的,未被访问过的鳄鱼(距离岛15+D范围内的鳄鱼)
            if (G.Crocs[i][j] == 1 && IsNear(50, 50, i, j, 15 + D) && Visited[i][j] == false)
                mark = DFS(PtrG, i, j, D);
            if (mark)
                break;
        }
        if (mark)
            break;
        // if (i == 14)
        //     pause();
    }
    if (mark)
        printf("Yes");
    else
        printf("No");
    return 0;
}
void pause(void)
{
    return;
}
void Insert(int x1, int y1, int D, PtrGraph PtrG)
{
    PtrG->Crocs[x1 + 50][y1 + 50] = 1;
    if ((abs(x1) + D) >= 50 || (abs(y1) + D) >= 50)
    {
        PtrG->Up[x1 + 50][y1 + 50] = true;
    }
}
int DFS(PtrGraph PtrG, int x1, int y1, int D)
{ //深度优先搜索
    int i, j, mark;
    mark = 0;
    Visited[x1][y1] = true;
    if (PtrG->Up[x1][y1] == true)
        return 1;
    for (i = 0; i < 100; i++)
    {
        for (j = 0; j < 100; j++)
        { //查找跳到的鳄鱼附近D距离内的未被访问过的鳄鱼,并遍历它
            if (PtrG->Crocs[i][j] == 1 && IsNear(x1, y1, i, j, D) && Visited[i][j] == false)
                mark = DFS(PtrG, i, j, D); //深度遍历点(i,j)
            if (mark)
                break;
        }
        if (mark)
            break;
    }
    if (mark)
        return 1;
    else
        return 0;
}
int IsNear(int x1, int y1, int x2, int y2, int D)
{ //判断能否跳到,能挑到返回1
    int dx = x1 - x2;
    int dy = y1 - y2;
    if ((dx * dx + dy * dy) <= D * D)
        return 1;
    else
        return 0;
}

3.六度空间

注意:C 库函数memset()-可以很方便的对字符数组进行初始化;C 库函数printf()的详细介绍。

/*题意分析:六度空间理论,判定一张图中符合六度空间的结点站所有节点的百分比;首先输入顶点数N和边数M;
最后打印对每个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每个结节点输出一行,格式为“结点编号:(空格)百分比%”。*/
/*思路:
1,使用邻接矩阵存储,广度优先搜索方法;
2,实现广度优先搜索关于层数的判别:last2保存每层最后一个结点,last1保存每次向下搜索层的最后一个结点;当last2==当前顶点V时,将last2=last1,层数level++;
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* 此为memset()需调用的库函数*/
#include <stdbool.h>

/*队列的矩阵存储实现*/
#define ElementType int
#define MaxSize 1001
typedef struct QNode *Queue;
struct QNode
{
    ElementType Data[MaxSize];
    int rear;  //记录尾元素序号
    int front; //记录头元素序号
};

/*图的邻接矩阵表示方法*/
#define MaxVertexNum 1001 /*最大顶点数*/
#define INFINITY 65535   /*无穷设为双字节无符号整数的最大值65535*/

bool Visited[MaxVertexNum] = {false}; //结点是否被访问过的标志

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个顶点但没有边的图 */
void InsertEdge(MGraph Graph, Edge E); /*插入边*/
MGraph BuildGraph();                   /*建立图*/

/*队列相关函数声明(线性存储)*/
Queue CreateQueue();                     // 04.创建空队
void AddQ(Queue PtrQ, ElementType item); // 02.入队列,队列采用循环结构可以最大限度利用空间
ElementType DeleteQ(Queue PtrQ);         // 03.出队列
int IsEmpty(Queue PtrQ);                 //判断是否为空

/*BFS和DFS相关函数声明*/
bool IsEdge(MGraph Graph, Vertex V, Vertex W);
int BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex));  /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
void DFS(MGraph Graph, Vertex S, void (*Visit)(Vertex)); /* 以S为出发点对邻接矩阵存储的图Graph进行DFS搜索 */
void Visit(Vertex);

int main(void)
{
    int value;
    float percent;
    MGraph G;
    G = BuildGraph();
    value = 0; /*与目标结点不超过六层的结点数*/
    for (Vertex i = 0; i < G->Nv; i++) 
    {
        value = BFS(G, i, Visit);
        memset(Visited, false, G->Nv); /*每次都要初始化Visited[]*/
        percent = (((float)value+1) / (float)G->Nv);
        printf("%d: %.2f%%\n", i+1, percent*100);
    }
    return 0;
}

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)
{/*输入边的起始1开始,这里要做修改*/
    /* 插入边 <V1, V2> */
    Graph->G[(E->V1)-1][(E->V2)-1] = E->Weight;
    /* 若是无向图,还要插入边<V2, V1> */
    Graph->G[(E->V2)-1][(E->V1)-1] = 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", &E->V1, &E->V2);
            E->Weight = 1;
            /* 注意:如果权重不是整型,Weight的读入格式要改 */
            InsertEdge(Graph, E);
        }
    }

    // /* 如果顶点有数据的话,读入数据 */
    // for (V = 0; V < Graph->Nv; V++)
    //     scanf(" %c", &(Graph->Data[V]));

    return Graph;
}

/* 深度优先搜索实现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;
}

void Visit(Vertex V)
{
    printf(" %d", V);
}

/* Visited[]为全局变量,已经初始化为false */
int BFS(MGraph Graph, Vertex S, void (*Visit)(Vertex))
{ /* 以S为出发点对邻接矩阵存储的图Graph进行BFS搜索 */
    int level, count;
    level = -1;
    count = 0;
    Queue Q;
    Vertex V, W, last1, last2;
    Q = CreateQueue(MaxSize); /* 创建空队列, MaxSize为外部定义的常数 */
    /* 访问顶点S:此处可根据具体访问需要改写 */
    // Visit(S);
    Visited[S] = true; /* 标记S已访问 */
    AddQ(Q, S);        /* S入队列 */
    level = 0;
    last2=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入队列 */
                count++;
                last1 = W; /*当前顶点V的最后一个邻接点下标*/
            }
        if(V==last2)/*当前层的最后一个顶点下标V的邻接点已经全部找到*/
        {
            last2=last1;//保存下一层的最后一个顶点下标
            level++;/*第ans层遍历结束*/
        }
        if (level==6)
        break;
        
    }              /* while结束*/
    return count;
}
/* Visited[]为全局变量,已经初始化为false */
void DFS(MGraph Graph, Vertex S, void (*Visit)(Vertex))
{
    Vertex W;
    /*访问顶点S:此处可以根据具体访问需要改写*/
    Visit(S);
    Visited[S] = true;              /*标记S已访问*/
    for (W = 0; W < Graph->Nv; W++) /*对图中的每个顶点W*/
    {                               /*若W是S的邻接点且未被访问过*/
        if (!Visited[W] && IsEdge(Graph, S, W))
        {
            DFS(Graph, W, Visit);
        }
    }
}

// 04.创建空队
Queue CreateQueue()
{
    Queue Q;
    Q = (Queue)malloc(sizeof(struct QNode));
    Q->front = 0;
    Q->rear = MaxSize;
    return Q;
}
// 02.入队列,队列采用循环结构可以最大限度利用空间
void AddQ(Queue PtrQ, ElementType item)
{
    if ((PtrQ->rear + 1) % MaxSize == PtrQ->front)
    {
        printf("队列满");
        return;
    }
    PtrQ->rear = (PtrQ->rear + 1) % MaxSize;
    PtrQ->Data[PtrQ->rear] = item;
}
// 03.出队列
ElementType DeleteQ(Queue PtrQ)
{
    ElementType item;
    if (PtrQ->front == PtrQ->rear)
    {
        printf("队列空");
        return 0;
    }
    PtrQ->front = (PtrQ->front + 1) % MaxSize;
    return (PtrQ->Data[PtrQ->front]);
}
//判断是否空
int IsEmpty(Queue PtrQ)
{
    if (PtrQ->front == PtrQ->rear)
    {
        // printf("队列空");
        return 1;
    }
    else
        return 0;
}

结束

课程来源:浙江大学数据结构慕课MOOC

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值