浙江大学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];
}
}
}
}