浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第七讲)

浙江大学MOOC数据结构-陈越、何钦铭 编程练习题(第七讲)

在这里插入图片描述
编程说明
编程环境:平台运行
编程语言:C

第一题代码

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

#define MaxVertexNum 100 /* 最大顶点数设为100 */
#define INFINITY 65535   /* ∞设为双字节无符号整数的最大值65535*/
typedef int Vertex;      /* 用顶点下标表示顶点,为整型 */
typedef int WeightType;  /* 边的权值设为整型 */

/* 边的定义 */
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]; /* 邻接矩阵 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */


MGraph BuildGraph();
MGraph CreateGraph(int VertexNum);
void InsertEdge(MGraph Graph, Edge E);
void FindAnimal(MGraph Graph);
void Floyd(MGraph Graph, WeightType D[][MaxVertexNum]);
WeightType FindMaxDist(WeightType D[][MaxVertexNum],Vertex i, int N);

int main()
{
    MGraph G = BuildGraph();
    FindAnimal( G );
    return 0;
}

MGraph BuildGraph()
{
    MGraph Graph;
    Edge E;
    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);
            E->V1--;E->V2--; /* 起始编号从0开始 */
            InsertEdge(Graph, E);
        }
    }
    return Graph;
}

MGraph CreateGraph(int VertexNum)
{
    /* 初始化一个有VertexNum个顶点但没有边的图 */
    Vertex V, W;
    MGraph Graph;

    Graph = (MGraph)malloc(sizeof(struct GNode));/* 建立图 */
    Graph->Ne = 0;
    Graph->Nv = VertexNum;

    /* 初始化邻接矩阵 */
    /* 注意:这里默认顶点编号从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;
}

void FindAnimal(MGraph Graph)
{
    WeightType D[MaxVertexNum][MaxVertexNum], MaxDist, MinDist;
    Vertex Animal, i;

    Floyd(Graph,D);

    MinDist = INFINITY;
    for(i=0; i<Graph->Nv; i++)
    {
        MaxDist = FindMaxDist(D, i, Graph->Nv);
        if ( MaxDist == INFINITY )
        { /* 说明有从i无法变出的动物 */
            printf("0\n");
            return;
        }
        if(MaxDist < MinDist) /* 找到最长距离更小的动物 */
        {
            MinDist=MaxDist;
            Animal=i+1;/* 更新距离,记录编号 */
        }
    }
    printf("%d %d\n", Animal, MinDist);
}

void Floyd(MGraph Graph, WeightType D[][MaxVertexNum])
{
    Vertex i, j, k;
    /* 初始化 */
    for(i=0; i<Graph->Nv; i++)
    {
        for(j=0; j<Graph->Nv; j++)
        {
            D[i][j]=Graph->G[i][j];
        }
    }

    for(k=0; k<Graph->Nv; k++)
        for(i=0; i<Graph->Nv; i++)
            for(j=0; j<Graph->Nv; j++)
                if(D[i][k]+D[k][j]<D[i][j])
                {
                    D[i][j]=D[i][k]+D[k][j];
//                    if(i==j && D[i][j]<0)/* 若发现负值圈 */
//                    {
//                        return false;/* 不能正确解决,返回错误标记 */
//                    }
                }
}

WeightType FindMaxDist(WeightType D[][MaxVertexNum],Vertex i, int N)
{
    WeightType MaxDist;
    Vertex j;

    MaxDist=0;
    for(j=0; j<N; j++)/* 找出i到其他动物j的最长距离 */
    {
        if(i!=j && D[i][j]>MaxDist)
            MaxDist=D[i][j];
    }

    return MaxDist;
}

第二题代码

参考自https://www.cnblogs.com/AndyHY-Notes/p/12631202.html

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

#define MAXSIZE 101

typedef struct Coordinate{//鳄鱼的坐标
    int x;
    int y;
} Coordinate;
typedef struct FirstNode{ //存第一次跳的鳄鱼坐标
    int dis;      //距离的平方
    int index;    //对应到鳄鱼数组的下标
}FirstNode;
typedef struct QNode{
    int index;
    struct QNode *next;
} QNode, *Queue;  //队列

int distance[MAXSIZE];
int path[MAXSIZE];

Queue createQueue();
void pushQueue(Queue queue, int data);
int popQueue(Queue queue);
bool emptyQueue(Queue queue);
void quickSort(FirstNode a[], int low, int high);
int firstJump(Coordinate crocodiles[], int N, int D);
int BFS(Coordinate crocodiles[], int N, int D, int first);
bool canFirstJump(int x, int y, int D);
bool canJump(int x1, int y1, int x2, int y2, int D);
bool canEscape(int x, int y, int D);

int main()
{
    int N, D, x, y;
    scanf("%d %d", &N, &D);

    if(D + 7.5 >= 50) //直接跳到岸上,不踩鳄鱼,应对测试点5
    {
        printf("1\n");
        return 0;
    }

    Coordinate crocodiles[MAXSIZE];
    for (int i = 1; i <= N; i++)
    {
        scanf("%d %d", &x, &y);
        crocodiles[i].x = x;
        crocodiles[i].y = y;
        distance[i] = -1;   //顺便把这个数组也初始化了
        path[i] = -1;       //顺便把这个数组也初始化了
    }

    int index = firstJump(crocodiles, N, D);
    if (index)        //能跳到岸上
    {
        int dis = distance[index] + 1;
        int n = 0, ret[MAXSIZE];
        while(index != -1)
        {
            ret[n++] = index;
            index = path[index]; //index变为前一个顶点的index
        }
        printf("%d\n", dis);
        for (int i = n - 1; i >= 0; i--)
        {
            printf("%d %d\n", crocodiles[ret[i]].x, crocodiles[ret[i]].y);
        }
    }
    else//不能跳到岸上
    {
        printf("0\n");
    }

    return 0;
}

//创建队列,返回链表的哨兵结点//所谓的队列其实就是链表连接的节点
Queue createQueue()
{
    Queue queue = (Queue) malloc(sizeof(QNode));
    queue->index = 0;
    queue->next = NULL;
    return queue;
}

//入队,尾插法
void pushQueue(Queue queue, int data)
{
    Queue rear = queue;
    while(rear->next) rear = rear->next;
    Queue newNode = (Queue) malloc(sizeof(QNode));
    newNode->index = data;
    newNode->next = NULL;
    rear->next = newNode;
}

//出队,删除链表第一个结点
int popQueue(Queue queue)
{
    if(emptyQueue(queue)) return 0;
    Queue deleteNode = queue->next;
    int ret = deleteNode->index;
    queue->next = deleteNode->next;
    free(deleteNode);
    return ret;
}

//队列是否为空
bool emptyQueue(Queue queue)
{
    return queue->next == NULL;
}

//快速排序,递增顺序
void quickSort(FirstNode a[], int low, int high)
{
    if(low >= high) return;
    int i = low, j = high;
    int tmpDis = a[low].dis;
    int tmpIndex = a[low].index;
    while(i < j)
    {
        while(i < j && a[j].dis >= tmpDis) j--;
        a[i] = a[j];
        while(i < j && a[i].dis <= tmpDis) i++;
        a[j] = a[i];
    }
    a[i].dis = tmpDis;
    a[i].index = tmpIndex;
    quickSort(a, low, i-1);
    quickSort(a, i+1, high);
}

//第一次跳,用一个数组存第一下跳能够跳到的鳄鱼的距离的平方和下标
int firstJump(Coordinate crocodiles[], int N, int D)
{
    FirstNode first[MAXSIZE];
    int j = 0, x, y;
    for(int i = 1; i <= N; i++)
    {
        x = crocodiles[i].x;
        y = crocodiles[i].y;
        if (canFirstJump(x, y, D))
        {
            first[++j].dis = pow(x,2) + pow(y,2);
            first[j].index = i;
        }
    }
    quickSort(first, 1, j);    //将first按照距离的平方递增排序
    for(int i = 1; i <= j; i++) //按照从小到大的顺序BFS
    {
        int index = BFS(crocodiles, N, D, first[i].index);
        if(index)
        {
            return index;
        }
        else  //如果以这个鳄鱼为第一个顶点跳不到岸上,就要重置下面这两个数组
        {
            for (int j = 1; j <= N; j++)
            {
                distance[j] = -1;
                path[j] = -1;
            }
        }
    }
    return 0;
}

//广度优先搜索
int BFS(Coordinate crocodiles[], int N, int D, int first)
{
    int x1, y1, x2, y2;
    Queue queue = createQueue();
    pushQueue(queue, first);
    distance[first] = 1;          //将第一个鳄鱼的距离赋值为1
    while(!emptyQueue(queue))
    {
        int index = popQueue(queue);
        x1 = crocodiles[index].x;
        y1 = crocodiles[index].y;
        if (canEscape(x1, y1, D))
            return index;              //能跳到岸上,就提前返回当前鳄鱼下标
        for(int j = 1; j <= N; j++)
        {
            x2 = crocodiles[j].x;
            y2 = crocodiles[j].y;
            if(distance[j] == -1 && canJump(x1, y1, x2, y2, D))
            {
                distance[j] = distance[index] + 1;  //更新距离
                path[j] = index;                //更新路径
                pushQueue(queue, j);
            }
        }
    }

    return 0;//不能跳到岸上就返回0,由于下标是从1开始的,因此可以以此判断是否成功跳到岸上
}

//判断是否能从岛上跳到鳄鱼上
bool canFirstJump(int x, int y, int D)
{
    if (abs(x) <= 7.5 && abs(y) <= 7.5)
        return false;                       //鳄鱼在岛内不算,应对测试点3
    return pow(x, 2) + pow(y, 2) <= pow(D + 7.5, 2);
}

//判断是否能从一只鳄鱼跳到另一只鳄鱼上
bool canJump(int x1, int y1, int x2, int y2, int D)
{
    if (abs(x2) >= 50 || abs(y2) >= 50)
        return false;                       //鳄鱼在岸上不算,应对测试点3
    return pow(x1 - x2, 2) + pow(y1 - y2, 2) <= pow(D, 2);
}

//判断是否能从鳄鱼跳到岸上
bool canEscape(int x, int y, int D)
{
    return (abs(x) + D >= 50 || abs(y) + D >= 50);
}

第三题代码

参考自 https://www.cnblogs.com/yuxiaoba/p/8342538.html

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

#define MAXVEX 501
#define INFINITY  65535

void CreateGraph();
void Dijkstra(int v);

int G[MAXVEX][MAXVEX][2], Nv, Ne;
int know[MAXVEX];     //know[]=1表示求得最短路径
int distance[MAXVEX]; //表示求的最短距离
int pay[MAXVEX];      //表示最少费用

int main()
{
    int s, d;
    scanf("%d %d %d %d", &Nv, &Ne, &s, &d);
    CreateGraph();
    Dijkstra(s);
    if(distance[d] < INFINITY)
    {
        printf("%d %d", distance[d], pay[d]);
    }

    return 0;
}

void CreateGraph()
{
    //用邻接矩阵表示图
    int dn, f;//dn表示距离,f表示费用
    int v1, v2;

    for(int i=0; i<Nv; i++)
    {
        for(int j=0; j<Nv; j++)
        {
            G[i][j][0] = INFINITY; //初始化
            G[i][j][1] = INFINITY;
        }
    }

    for(int i=0; i<Ne; i++)//注意这里是读入边
    {
        scanf("%d %d %d %d", &v1, &v2, &dn, &f);
        G[v1][v2][0] = dn;
        G[v2][v1][0] = dn;
        G[v1][v2][1] = f;
        G[v2][v1][1] = f;
    }
}

void Dijkstra(int v)
{
    int k;
    int min, cost;
    //求从v结点到其他各结点的最短距离
    for(int i=0; i<Nv; i++)
    {
        know[i] = 0;
        distance[i] = G[v][i][0]; //将与v点有连接的结点加上距离
        pay[i] = G[v][i][1];
    }

    know[v] = 1;
    distance[v] = 0;  //V到V距离为0
    pay[v] = 0;

    for(int i=1; i<Nv; i++)
    {
        //寻找与V节点相连距离最短的节点
        min = INFINITY;
        for(int j=0; j<Nv; j++)
        {
            if( !know[j] && distance[j] < min)
            {
                k = j;
                min = distance[j];
                cost = pay[j];
            }
        }

        know[k] = 1;

        for(int j=0; j<Nv; j++)
        {
            //修正最短路径和距离
            if( !know[j] && (min + G[k][j][0] < distance[j]) )
            {
                distance[j] = min + G[k][j][0];
                pay[j] = cost + G[k][j][1];
            }
            else if( !know[j] && (min + G[k][j][0] == distance[j]) && (cost + G[k][j][1] < pay[j]) )
            {
                pay[j] = cost + G[k][j][1];
            }
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值