哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是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
(1)解题思路:
1.做该题时首先要明确要用数据结构:(这样不仅能够方便我们解题同时能够减少时间的复杂度)
①:理解题目以及考点:题目本质上就是基于图的遍历。
②:一开始我们画出关于人在鳄鱼中跳的草图方便我们理解题目,因此既然我们是用草图进行理解的,则想到图的数据结构进行解题,这就是为什么我要用图的数据结构进行解题的原因。
2.明确我所用的数据结构需要的东西或需要理解的算法:
①:在用图的算法时要理解两个东西:一个是顶点,另一个是边。
图的顶点和边是一个抽象的概念,并不是一个具体的概念。因此图的顶点要理解为有某种属性的对象(即并不一定是一个点才是顶点)。边理解为对象之间的关系。
②:在用图的算法时一定要确定顶点和边分别是什么。边和顶点都可以不是唯一的,即只要有某种属性就可以表示为顶点(图中的顶点并不是存的是只有一种属性的对象可以是多种),同时边也同上,可以表示为不同对象之间的关系。
这里的顶点是:鳄鱼,岛,岸边。这里的边是:能从一个鳄鱼跳到另一个鳄鱼,一开始(从岛开始)能跳到的鳄鱼,鳄鱼可以跳到岸边的。
③:如何表示一个图:在这道题中我采用二维矩阵表示的是边的关系。
3.涉及的算法以及思路解题步骤(题目的具体分析理解和需要用到的算法):
①:先将能够从岛(抽象成数据0表示)开始跳到的鳄鱼(鳄鱼顶点抽象成1~N的数)先建立建立边的关系。
人一开始可以跳到的鳄鱼判断条件为:从(0,0)(起点)到鳄鱼坐标的距离小于岛的半径加上人可以跳的距离的值就是一开始可以跳到的鳄鱼。
②:再建立人在某一个鳄鱼上可以跳到另一个鳄鱼的关系。
这时人可以跳到的范围就不需要加上岛的半径。
③:我采用的是深度优先遍历的方式进行遍历:
实参为:图,当前所在的结点,人可以跳的距离。从主函数进入是开始的位置是0。
0行存的是一开始可以跳到的鳄鱼。
每次在一个位置的时候就进行判断可不可以从该位置直接跳到岸边。如果可以则在输出YES后再用exit(0)强制结束程序(return也可以)。如果不可以则用标记数组进行标记,表示从该位置的鳄鱼不可以跳到岸边,然后再找该鳄鱼的相邻鳄鱼(这里就是深度优先遍历的主要程序了)。
④:并不需要走到最后的顶点再进行判断能不能跳,而是每跳到一个鳄鱼身上就进行判断。
最短路径模板+解析——(FLoyd算法)_coderyzh的博客-CSDN博客_floyd算法
⑤涉及图的最小路径问题的求解算法:
图的五种最短路径算法_qq_35710556的博客-CSDN博客_最短路径算法
3.我的第一种方式(有问题可以不看) :
问题:为什么不能一行一行进行查找,同时利用过度的方式进行查找(按道理虽然不是foly算法,但是思路差不多啊)
//题目我理解有点错,应该是看最长的长度是多少,还有是根据给出的公式将它转为最小的公式
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX 200
#define tranMAX 1000//表示没有直接的关系
//这里较特殊要建立一个顶点的结构
struct topchart_tran {
int animal_num;//动物的标号
int sum_data;//表示总的长度
int max_length; //一行之中最大的长度
};
typedef struct topchart_tran topchart;
//图的结构
struct tu_tran {
int spot_sum;//点数
int bian_sum;//边数
int connection[MAX][MAX];//邻接矩阵
topchart animal[MAX];//顶点数据
};
typedef struct tu_tran *chart;
//边的结构
struct bian_tran {
int v1,v2;
int length;
};
typedef struct bian_tran *bian;
//边的创建,避免递归造成的麻烦
bian tran ;
chart create(int N);
void produce(chart head,int N,int M);
void chart_insert(chart head) ;
void fill_chart(chart head,int N);//重要之一
int finding(chart head,int hang,int lie,int N);
void fill_shuzu(chart head,int N);
void Printf_chart(chart head,int N) ;
int main() {
int N,M;
scanf("%d%d",&N,&M);
chart tu;
//初始化
tu=create(N);
//创建图
produce(tu,N,M);
// for(int i=1; i<=N; i++) {
// for(int j=1; j<=N; j++)
// printf(" %d",tu->connection[i][j]);
// printf("\n");
// }
//第二重要函数 ,进行比较一维数组并且进行输出
Printf_chart(tu,N);
}
//初始化
chart create(int N) {
chart head;
head=(chart)malloc(sizeof(struct tu_tran));
head->spot_sum=N;
head->bian_sum=0;
//注意无论是一维还是二维都是从1开始存
for(int i=1; i<=N; i++) {
head->animal[i].animal_num=i;
head->animal[i].max_length=head->animal[i].sum_data=0;
}
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
if(i!=j)
head->connection[i][j]=tranMAX;
else
head->connection[i][j]=0;//即自己变自己不需要知道
}
}
return head;
}
//创建图
void produce(chart head,int N,int M) {
tran=(bian)malloc(sizeof(struct bian_tran));
for(int i=1; i<=M; i++) {
scanf("%d%d%d",&tran->v1,&tran->v2,&tran->length);
chart_insert(head);
}
//将列进行填充完整 -->第一重要函数
fill_chart(head,N);//w为0时进入从不为0处找,找到时还要进行比较,新的更小就进行交换
//填充完毕:算出最小长度+找出每一行的最大长度--》 得到完整的一维数组
// fill_shuzu(head,N);
}
//图的插入,即建立
void chart_insert(chart head) {
head->connection[tran->v1][tran->v2]=tran->length;
head->connection[tran->v2][tran->v1]=tran->length;
}
//一行一行的进行填充foly算法
void fill_chart(chart head,int N) {
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
for(int k=1;k<=N;k++) {
if(head->connection[i][j]>head->connection[i][k]+head->connection[k][j]){
head->connection[i][j]=head->connection[i][k]+head->connection[k][j];
}
}
}
}
}
//输出
//进行比较一维数组并且进行输出
void Printf_chart(chart head,int N) {
int index=0;
int min= tranMAX;
int max;
//在满足可以变为所有动物的要求的前提下找出长度最小的动物(不要理解错了)
for(int i=1;i<=N;i++){
max=0;
for(int j=1;j<=N;j++){
if(max<head->connection[i][j]){
max=head->connection[i][j];
}
}
if(min>max){//获得长度最小的 ,不能是等于要满足最小的编号
min=max;
index=i;
}
}
if(index==0){
printf("0\n");
}else{
printf("%d %d\n",index,min);
}
}
//问题一:没有完全理解题目:因该找出所有的最小的公式
//输出的方式有问题
//3 3
//1 3 6
//3 1 6
//2 1 4
// topchart min;
// min=head->animal[1];
// for(int i=2; i<=N; i++) {
如果有若干只动物都可以备选,则输出编号最小的那只。--三种情况 :一个最小但是有一个列为空。
输出编号最小的那只,想法:列有一个为空且有相等时就进行交换,不然就不用进行交换
》扫描一次即可,相等时先判断,不为空就直接跳过直接跳过一定要注意这个特殊要求
// if(head->animal[i].max_length==min.max_length) {
// for(int j=1;j<=N;j++){
// if(head->connection[min.animal_num][j]==tranMAX){
// min=head->animal[i];
// break;
// }
// }
// continue;
// }
// else if(head->animal[i].max_length<min.max_length)
// min=head->animal[i];
// }
如果只带1只动物是不可能完成所有变形要求的,则输出0。-->也就是最小长度的列存在和至少一个动物没有关系
判断最小的列是不是有一个为空
// for(int i=1;i<=N;i++){
// if(head->connection[min.animal_num][i]==tranMAX){
// printf("0\n");
// exit(0);
// }
// }
// printf("%d %d\n",min.animal_num,min.max_length);
4. 成功
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX 200
#define tranMAX 1000//表示没有直接的关系
//这里较特殊要建立一个顶点的结构
struct topchart_tran {
int animal_num;//动物的标号
int sum_data;//表示总的长度
int max_length; //一行之中最大的长度
};
typedef struct topchart_tran topchart;
//图的结构
struct tu_tran {
int spot_sum;//点数
int bian_sum;//边数
int connection[MAX][MAX];//邻接矩阵
topchart animal[MAX];//顶点数据
};
typedef struct tu_tran *chart;
//边的结构
struct bian_tran {
int v1,v2;
int length;
};
typedef struct bian_tran *bian;
//边的创建,避免递归造成的麻烦
bian tran ;
chart create(int N);
void produce(chart head,int N,int M);
void chart_insert(chart head) ;
void fill_chart(chart head,int N);//重要之一
int finding(chart head,int hang,int lie,int N);
void fill_shuzu(chart head,int N);
void Printf_chart(chart head,int N) ;
int main() {
int N,M;
scanf("%d%d",&N,&M);
chart tu;
//初始化
tu=create(N);
//创建图
produce(tu,N,M);
// for(int i=1; i<=N; i++) {
// for(int j=1; j<=N; j++)
// printf(" %d",tu->connection[i][j]);
// printf("\n");
// }
//第二重要函数 ,进行比较一维数组并且进行输出
Printf_chart(tu,N);
}
//初始化
chart create(int N) {
chart head;
head=(chart)malloc(sizeof(struct tu_tran));
head->spot_sum=N;
head->bian_sum=0;
//注意无论是一维还是二维都是从1开始存
for(int i=1; i<=N; i++) {
head->animal[i].animal_num=i;
head->animal[i].max_length=head->animal[i].sum_data=0;
}
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
if(i!=j)
head->connection[i][j]=tranMAX;
else
head->connection[i][j]=0;//即自己变自己不需要知道
}
}
return head;
}
//创建图
void produce(chart head,int N,int M) {
tran=(bian)malloc(sizeof(struct bian_tran));
for(int i=1; i<=M; i++) {
scanf("%d%d%d",&tran->v1,&tran->v2,&tran->length);
chart_insert(head);
}
//将列进行填充完整 -->第一重要函数
fill_chart(head,N);//w为0时进入从不为0处找,找到时还要进行比较,新的更小就进行交换
}
//图的插入,即建立
void chart_insert(chart head) {
head->connection[tran->v1][tran->v2]=tran->length;
head->connection[tran->v2][tran->v1]=tran->length;
}
//一行一行的进行填充foly算法
void fill_chart(chart head,int N) {
for(int k=1; k<=N; k++) {
for(int i=1; i<=N; i++) {
for(int j=1;j<=N;j++) {
if(head->connection[i][j]==0)
continue;
if(head->connection[i][j]>head->connection[i][k]+head->connection[k][j]){
head->connection[i][j]=head->connection[i][k]+head->connection[k][j];
}
}
}
}
}
//输出
//进行比较一维数组并且进行输出
void Printf_chart(chart head,int N) {
int index=0;
int min= tranMAX;
int max;
//在满足可以变为所有动物的要求的前提下找出长度最小的动物(不要理解错了)
for(int i=1;i<=N;i++){
max=0;
for(int j=1;j<=N;j++){
if(max<head->connection[i][j]){
max=head->connection[i][j];
}
}
if(min>max){//获得长度最小的 ,不能是等于因为要满足最小的编号
min=max;
index=i;
}
}
if(index==0){
printf("0\n");
}else{
printf("%d %d\n",index,min);
}
}
错误改进:
//直接变的符号一定是最短的,因此找一个到另一个的符号(这两个没有直接符号)一定是先找已有的直接符号进行直接的转换。
//题目要求的即为是一个动物转为其他动物的符号的和的长度最小
//该题目首先总体的算法要进行分析,该题是一个对象和另一个对象之间的关系。
//即多对多的关系-->即图的算法。
//首先先找它的顶点:很明显顶点就是各个动物作为顶点(这道题比上一道要简单很多,因为它的顶点是唯一的)
//在找它的边为:动物之间有直接转换关系的
//还要注意边是否有有权值:在这里即表示的是直接转换的长度
//在该题中最关键的是利用遍历的方式在已经有直接转换中找出没有直接转换为另一个动物的符号,即
//所有的列必须要有和该行对应的字符长
//我采用二维数组的方式进行存图 -->注意和邻接表的区别
//如果只带1只动物是不可能完成所有变形要求的,则输出0。-->也就是最小长度的列存在和至少一个动物没有关系
//如果有若干只动物都可以备选,则输出编号最小的那只。--三种情况 :一个最小但是有一个列为空。
// 输出编号最小的那只,想法:列有一个为空且有相等时就进行交换,不然就不用进行交换
//》扫描一次即可,相等时先判断直接跳过一定要注意这个特殊要求
//题目我理解有点错,应该是看最长的长度是多少,还有是根据给出的公式将它转为最小的公式
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX 200
#define tranMAX 1000//表示没有直接的关系
//这里较特殊要建立一个顶点的结构
struct topchart_tran {
int animal_num;//动物的标号
int sum_data;//表示总的长度
int max_length; //一行之中最大的长度
};
typedef struct topchart_tran topchart;
//图的结构
struct tu_tran {
int spot_sum;//点数
int bian_sum;//边数
int connection[MAX][MAX];//邻接矩阵
topchart animal[MAX];//顶点数据
};
typedef struct tu_tran *chart;
//边的结构
struct bian_tran {
int v1,v2;
int length;
};
typedef struct bian_tran *bian;
//边的创建,避免递归造成的麻烦
bian tran ;
chart create(int N);
void produce(chart head,int N,int M);
void chart_insert(chart head) ;
void fill_chart(chart head,int N);//重要之一
int finding(chart head,int hang,int lie,int N);
void fill_shuzu(chart head,int N);
void Printf_chart(chart head,int N) ;
int main() {
int N,M;
scanf("%d%d",&N,&M);
chart tu;
//初始化
tu=create(N);
//创建图
produce(tu,N,M);
// for(int i=1; i<=N; i++) {
// for(int j=1; j<=N; j++)
// printf(" %d",tu->connection[i][j]);
// printf("\n");
// }
//第二重要函数 ,进行比较一维数组并且进行输出
Printf_chart(tu,N);
}
//初始化
chart create(int N) {
chart head;
head=(chart)malloc(sizeof(struct tu_tran));
head->spot_sum=N;
head->bian_sum=0;
//注意无论是一维还是二维都是从1开始存
for(int i=1; i<=N; i++) {
head->animal[i].animal_num=i;
head->animal[i].max_length=head->animal[i].sum_data=0;
}
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
if(i!=j)
head->connection[i][j]=tranMAX;
else
head->connection[i][j]=0;//即自己变自己不需要知道
}
}
return head;
}
//创建图
void produce(chart head,int N,int M) {
tran=(bian)malloc(sizeof(struct bian_tran));
for(int i=1; i<=M; i++) {
scanf("%d%d%d",&tran->v1,&tran->v2,&tran->length);
chart_insert(head);
}
//将列进行填充完整 -->第一重要函数
fill_chart(head,N);//w为0时进入从不为0处找,找到时还要进行比较,新的更小就进行交换
//填充完毕:算出最小长度+找出每一行的最大长度--》 得到完整的一维数组
// fill_shuzu(head,N);
}
//图的插入,即建立
void chart_insert(chart head) {
head->connection[tran->v1][tran->v2]=tran->length;
head->connection[tran->v2][tran->v1]=tran->length;
}
//一行一行的进行填充foly算法
void fill_chart(chart head,int N) {
for(int i=1; i<=N; i++) {
for(int j=1; j<=N; j++) {
for(int k=1;k<=N;k++) {
if(head->connection[i][j]>head->connection[i][k]+head->connection[k][j]){
head->connection[i][j]=head->connection[i][k]+head->connection[k][j];
}
}
}
}
}
//输出
//进行比较一维数组并且进行输出
void Printf_chart(chart head,int N) {
int index=0;
int min= tranMAX;
int max;
//在满足可以变为所有动物的要求的前提下找出长度最小的动物(不要理解错了)
for(int i=1;i<=N;i++){
max=0;
for(int j=1;j<=N;j++){
if(max<head->connection[i][j]){
max=head->connection[i][j];
}
}
if(min>max){//获得长度最小的 ,不能是等于要满足最小的编号
min=max;
index=i;
}
}
if(index==0){
printf("0\n");
}else{
printf("%d %d\n",index,min);
}
}
//问题一:没有完全理解题目:因该找出所有的最小的公式
//输出的方式有问题
//3 3
//1 3 6
//3 1 6
//2 1 4
// topchart min;
// min=head->animal[1];
// for(int i=2; i<=N; i++) {
如果有若干只动物都可以备选,则输出编号最小的那只。--三种情况 :一个最小但是有一个列为空。
输出编号最小的那只,想法:列有一个为空且有相等时就进行交换,不然就不用进行交换
》扫描一次即可,相等时先判断,不为空就直接跳过直接跳过一定要注意这个特殊要求
// if(head->animal[i].max_length==min.max_length) {
// for(int j=1;j<=N;j++){
// if(head->connection[min.animal_num][j]==tranMAX){
// min=head->animal[i];
// break;
// }
// }
// continue;
// }
// else if(head->animal[i].max_length<min.max_length)
// min=head->animal[i];
// }
如果只带1只动物是不可能完成所有变形要求的,则输出0。-->也就是最小长度的列存在和至少一个动物没有关系
判断最小的列是不是有一个为空
// for(int i=1;i<=N;i++){
// if(head->connection[min.animal_num][i]==tranMAX){
// printf("0\n");
// exit(0);
// }
// }
// printf("%d %d\n",min.animal_num,min.max_length);