数据结构基础:P7.5-图(二)--->哈利·波特的考试
作者:互联网
本系列文章为浙江大学陈越、何钦铭数据结构学习笔记,前面的系列文章链接如下:
数据结构基础:P1-基本概念
数据结构基础:P2.1-线性结构—>线性表
数据结构基础:P2.2-线性结构—>堆栈
数据结构基础:P2.3-线性结构—>队列
数据结构基础:P2.4-线性结构—>应用实例:多项式加法运算
数据结构基础:P2.5-线性结构—>应用实例:多项式乘法与加法运算-C实现
数据结构基础:P3.1-树(一)—>树与树的表示
数据结构基础:P3.2-树(一)—>二叉树及存储结构
数据结构基础:P3.3-树(一)—>二叉树的遍历
数据结构基础:P3.4-树(一)—>小白专场:树的同构-C语言实现
数据结构基础:P4.1-树(二)—>二叉搜索树
数据结构基础:P4.2-树(二)—>二叉平衡树
数据结构基础:P4.3-树(二)—>小白专场:是否同一棵二叉搜索树-C实现
数据结构基础:P4.4-树(二)—>线性结构之习题选讲:逆转链表
数据结构基础:P5.1-树(三)—>堆
数据结构基础:P5.2-树(三)—>哈夫曼树与哈夫曼编码
数据结构基础:P5.3-树(三)—>集合及运算
数据结构基础:P5.4-树(三)—>入门专场:堆中的路径
数据结构基础:P5.5-树(三)—>入门专场:File Transfer
数据结构基础:P6.1-图(一)—>什么是图
数据结构基础:P6.2-图(一)—>图的遍历
数据结构基础:P6.3-图(一)—>应用实例:拯救007
数据结构基础:P6.4-图(一)—>应用实例:六度空间
数据结构基础:P6.5-图(一)—>小白专场:如何建立图-C语言实现
数据结构基础:P7.1-图(二)—>树之习题选讲:Tree Traversals Again
数据结构基础:P7.2-图(二)—>树之习题选讲:Complete Binary Search Tree
数据结构基础:P7.3-图(二)—>树之习题选讲:Huffman Codes
数据结构基础:P7.4-图(二)—>最短路径问题
文章目录
一、题目描述
题目描述:
哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。
现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。
输入格式:
输入说明:输入第1行给出两个正整数N(≤100)
和M
,其中N
是考试涉及的动物总数,M
是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N
编号。随后M
行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100)
,数字之间用空格分隔。
输出格式:
输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。
输入样例:
6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80
输出样例:
4 70
二、题目理解
从下图可以看出,猫变成鱼最困难,需要6个字符。鱼变成猫最困难,需要6个字符。老鼠变成鱼和猫都只需要4个字符,因此选择带老鼠去。
我们来看个复杂的例子:现在输入样例如下,第一行输入结点数与边数,接下来输入结点及他们之间边的权值。
我们根据此画出图如下:
这个图比刚才那个图要复杂的多了,我们很难一眼看出来到底应该带哪只动物去是最合算的。那我们第一件要做的事情就是应该把任意两个动物之间的最短路径找出来。要找一个图里面任意一对顶点之间的最短路径,很显然用Floyd算法是最合适的。通过调用这个算法我们会得到一个表示最短距离的矩阵
D
\rm{D}
D,那么
D
(
i
,
j
)
\rm{D(i,j)}
D(i,j)就记录的是从顶点i
到顶点j
之间的最短距离。比方说这个120,他是第三行 第五列,意味着从顶点3到顶点5之间的最短距离是120。
那要回答Harry究竟应该带哪只动物去的这个问题的时候,我们首先检查每一行里面最大的那个数字。比如说第一行里面最大的数字是81,就意味着第一个动物变成第五个动物是最麻烦的。
那么到底应该带哪个动物去使得我们最难变的那个动物是最好变的呢?那也就是从我们圈出来的这6个最大值里面要找那个最小值,就在这 70。也就是说如果我们把4号带过去的话,那么他最困难的一个动物是要变成3,那最困难的咒语长度是70。那已经是所有其他最困难的咒语里面最容易的一个了,结论就是我们应该带4号动物去,最大距离是70。
三、程序框架搭建
在写这个main函数之前,我们先要规划一下我们到底要在main函数里面做哪几件事情。就这道题而言,我们可以把它非常简单的分成两步:①我要把输入读进来,并且构架起一个图②然后我要开始对这个图去做分析
整体框架如下:
四、选择动物
我们先来看怎么样实现这个FindAnimal这个函数,整体的函数框架如下:
相应代码如下:
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++ ) {
//找出第i个动物最远距离给MaxDist
MaxDist = FindMaxDist( D, i, Graph->Nv );
if ( MaxDist == INFINITY ) { /* 说明有从i无法变出的动物,图不连通,带一只动物不够 */
printf("0\n");
return;
}
if ( MinDist > MaxDist ) { /* 找到最长距离更小的动物 */
MinDist = MaxDist; Animal = i+1; /* 更新距离,记录动物的编号 */
}
}
printf("%d %d\n", Animal, MinDist);
}
找到最大距离代码如下:
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;
}
五、整体代码与实现
整体代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.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 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;
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;
}
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];
}
}
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++) {
//找出第i个动物最远距离给MaxDist
MaxDist = FindMaxDist(D, i, Graph->Nv);
if (MaxDist == INFINITY) { /* 说明有从i无法变出的动物,图不连通,带一只动物不够 */
printf("0\n");
return;
}
if (MinDist > MaxDist) { /* 找到最长距离更小的动物 */
MinDist = MaxDist; Animal = i + 1; /* 更新距离,记录动物的编号 */
}
}
printf("%d %d\n", Animal, MinDist);
}
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;
}
int main()
{
MGraph M = BuildGraph();
Floyd(M,M->G);
FindAnimal(M);
return 0;
}
运行,输入题目中的样例,结果如下:
标签:P7.5,MaxDist,Graph,---,WeightType,哈利,数据结构,动物,Nv 来源: https://blog.csdn.net/InnerPeaceHQ/article/details/122568482