0%

07-图4 哈利·波特的考试

​ 哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。

​ 现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。

输入格式:

​ 输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。

输出格式:

​ 输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。

输入样例:

1
2
3
4
5
6
7
8
9
10
11
12
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

输出样例:

1
4 70

分析:

  1. 每个动物实际是一个个顶点,两个动物间可以变幻实际是两个顶点有边,而魔咒的长度就是边的权重。
  2. 找最优动物实际是需要找出所有顶点到其它顶点的最短的最远距离。
  3. 求两点间的距离,Floyd算法。

编码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdlib.h>
#include <stdio.h>

#define MaxVertexNum 100
#define INFINITY 65535
#define MaxSize 1024

typedef int Vertex;// 用整形表示顶点
typedef int WeightType; // 权重

typedef struct GNode *PtrToGNode;
typedef PtrToGNode MGraph;
struct GNode {
//1.顶点数Nv
int Nv;
//2.边数Ne
int Ne;
//3.邻接矩阵二维数组G
WeightType G[MaxVertexNum][MaxVertexNum];
};

typedef struct ENode *PtrToENode;
typedef PtrToENode Edge;
struct ENode {
//1.无向边(V1,V2),V1 V2为顶点
Vertex V1, V2;
//2.权重Weight
WeightType Weight;
};


// 创建零图
MGraph CreateGraph(int VertexNum) {
// 1.创建一个有VertexNum个顶点0条边的图MGraph
Vertex V, W;
MGraph Graph;
Graph = (MGraph) malloc(sizeof(struct GNode));
Graph->Nv = VertexNum;
Graph->Ne = 0;
// 2.遍历,初始化二维数组,顶点的权重为无限大或-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>,二维数组的顶点V1,V2写入权重Weight
Graph->G[E->V1][E->V2] = E->Weight;
// 2.如果是无向图还需要插入反向点,对称矩阵
Graph->G[E->V2][E->V1] = E->Weight;
}

// 创建图,含顶点与边
MGraph BuildGraph() {
MGraph Graph;
Edge E;
int Nv, i;
//1.读入顶点个数,构造含有Nv个顶点无边的图
scanf("%d", &Nv);
Graph = CreateGraph(Nv);

// 2.读入边数Ne
scanf("%d", &(Graph->Ne));
if (Graph->Ne != 0) {
E = (Edge) malloc(sizeof(struct ENode));
for (i = 0; i < Graph->Ne; i++) {
// 3.循环读入一条边,并插入Graph中
scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
E->V1--;
E->V2--;
InsertEdge(Graph, E);
}
}
return Graph;
}

// 求两点i,j间的最短距离
void Floyd(MGraph Graph, WeightType D[][MaxVertexNum]) {
// 0.数组D[i][j]为i,j两点间的最短路径,path[i][j]为i,j最短路径,点j的前驱点
Vertex i, j, k;
// 1.初始化Vi,Vj的最短路径D为两点间的权重,路径path为-1
for (i = 0; i < Graph->Nv; i++) {
for (j = 0; j < Graph->Nv; j++) {
D[i][j] = Graph->G[i][j];
}
}
// 2.三重遍历,找到任意两点i,j间的最短距离及路径
for (k = 0; k < Graph->Nv; k++) {
for (i = 0; i < Graph->Nv; i++) {
for (j = 0; j < Graph->Nv; j++) {
// 3.如果找到新的k点,使得ik加kj距离小于原来的值,更新距离和路径
if (D[i][k] + D[k][j] < D[i][j]) {
D[i][j] = D[i][k] + D[k][j];
}
}
}
}
}

WeightType FindMaxDist(WeightType D[][MaxVertexNum], Vertex i, int N) {
WeightType MaxDist;
Vertex j;
MaxDist = 0;
for (j = 0; j < N; j++) {
if (i != j && D[i][j] > MaxDist) {
MaxDist = D[i][j];
}
}
return MaxDist;
}

void FindAnimal(MGraph Graph) {
WeightType D[MaxVertexNum][MaxVertexNum], MaxDist, MinDist;
Vertex Animal, i;
// 1.通过Floyd算法找到所有两点间最短的距离,保存在二维数组D中
Floyd(Graph, D);
MinDist = INFINITY;
// 2.遍历所有的顶点
for (i = 0; i < Graph->Nv; i++) {
// 3.找到当前点到其它点的最长距离
MaxDist = FindMaxDist(D, i, Graph->Nv);
// 4.如果该点与其它点无边,则打印o
if (MaxDist == INFINITY) {
printf("0\n");
return;
}
// 5.如果找到的MaxDist比之前的MinDist更小,则更新MinDist
if (MaxDist < MinDist) {
MinDist = MaxDist;
Animal = i + 1;
}
}
printf("%d %d\n", Animal, MinDist);
}

int main() {
// 1.输入并构造图-邻接矩阵
MGraph Graph = BuildGraph();
// 2.找到两点间最短的最长距离,最合适动物
FindAnimal(Graph);
return 0;
}

小结:

  1. 图的结构选择,基于Floyd算法,这里选用邻接矩阵。
  2. 因为动物编号是从0开始的,在插入边及最后输出时需要注意index。