PTA_2019春_074_哈利·波特的考试

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是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.判断是不是连通图,如果不是则输出0;
        2.多源最短路径,对联通图中的每一个顶点遍历,得到每一个顶点与其他顶点的最大长度*/
/*邻接矩阵,无向图*/
/*1.忘记加取址符
  2.错在对角线没有初始为0
  3.无解的输出位置错误 
  */
#include<stdio.h>
#include<stdlib.h>
typedef struct Gnode* MGraph;
struct Gnode {
	int Nv;  /*顶点数*/
	int Ne;  /*边数*/
	int G[101][101];  /*权重*/
};
/*边的定义,无权边*/
typedef struct Enode* Edge;
struct Enode {
	int V1, V2;
	int weight;/*权重*/
};
/*队列操作*/
typedef struct Qnode* ptrtoQnode;
struct Qnode {
	int* Data;/*data数组,*/
	int front, rear;/*队列头尾指针*/
	int maxsize;/*容量*/
};
typedef ptrtoQnode Queue;
int AddQ(Queue Q, int x);
Queue CreateQueue(int maxsize);
int isempty(Queue Q);
int DeleteQ(Queue Q);

/*操作函数*/
MGraph creatgraph(int size);
void insert(MGraph g, Edge e);
MGraph buildgraph(int N);
int isedge(MGraph graph, int a, int b);
void BFS(MGraph graph, int N, int* visited, int s);
void Floyd(MGraph graph,int weight[][101]);
/*队列操作*/
int AddQ(Queue Q, int x);
Queue CreateQueue(int maxsize);
int isempty(Queue Q);
int DeleteQ(Queue Q);

int main() {   /*注意此题从1开始*/
	int N;
	scanf("%d", &N);
	int* visited = (int*)malloc((N+1) * sizeof(int));
	int isanswer = 1;
	for (int i = 1; i < N+1; i++) {
		visited[i] = 0;
	}
	/*建立邻接矩阵*/
	MGraph graph = buildgraph(N);

	BFS(graph, N, visited, 1);/*以第一个顶点为起点,对图进行遍历,如果图中有顶点未被遍历过则说明不是联通图*/
	for (int i = 1; i < N + 1; i++) {
		if (visited[i] == 0)  {
			isanswer = 0;
			break;
		}
	}
	/*多源最短路径*/
	int weight[101][101];
	int shortest[101];
	Floyd(graph, weight);
	for (int i = 1; i < N + 1; i++) {
		int max = -1;
		for (int j = 1; j < N + 1; j++) {
			if (weight[i][j] > max && weight[i][j] != 20000) {
				max = weight[i][j];
			}	
		}
		shortest[i] = max;/*将与第i个顶点路径最长的存储*/
	}
	/*先将shortest存储*/
	int data[101];
	for (int i = 1; i < N + 1; i++) {
		data[i] = shortest[i];
	}
	/*对shortest排序,找出其最小值*/
	int j;
	int temp;
	for (int i = 1; i < N ; i++) {   /*shortest最小值即第一元素*/
		for (j = i + 1; j < N + 1; j++) {
			if (shortest[i] > shortest[j]) {
				temp = shortest[i];
				shortest[i] = shortest[j];
				shortest[j] = temp;
			}
		}
	}
	/*找出最小编号*/
	int answer;
	for (int i = 1; i < N + 1; i++) {
		if (shortest[1] == data[i]) {
			answer = i;
			break;
		}
	}
	if(isanswer == 1){
		printf("%d %d", answer, data[answer]);
	}
	else  printf("0");
	return 0;
}
MGraph creatgraph(int size) {/*初始化邻接矩阵*/
	int j;
	MGraph graph = (MGraph)malloc(sizeof(struct Gnode)); /*建图*/
	graph->Nv = size;
	graph->Ne = 0;
	/*初始化邻接矩阵*/
	for (int i = 1; i < graph->Nv+1; i++) {
		for (j = 1; j < graph->Nv+1; j++) {
			if(i==j){                                /*一开始没有将对角线处初始为0,导致最后多源最短路径出错*/
				graph->G[i][j] = 0; 
			}
			else{
				graph->G[i][j] = 20000;             /*设20000为无穷值,即两点不连通*/
			}
			                     
		}
	}
	return graph;
}
void insert(MGraph g, Edge e) {  /*注意此题为无向图*/
	g->G[e->V1][e->V2] = e->weight;
	g->G[e->V2][e->V1] = e->weight;
}
MGraph buildgraph(int N) {
	MGraph G;
	G = creatgraph(N);
	scanf("%d", &G->Ne);
	if (G->Ne != 0) {
		Edge E = (Edge)malloc(sizeof(struct Enode));
		for (int i = 0; i < G->Ne; i++) {
			scanf("%d %d %d", &E->V1, &E->V2,&E->weight);
			insert(G, E);
		}
	}
	return G;
}
Queue CreateQueue(int maxsize) {
	Queue Q = (Queue)malloc(sizeof(struct Qnode));
	Q->Data = (int*)malloc(maxsize * sizeof(int));
	Q->front = Q->rear = 0;
	Q->maxsize = maxsize;
	return Q;
}
int AddQ(Queue Q, int x) {
	Q->rear = (Q->rear + 1) % (Q->maxsize);
	Q->Data[Q->rear] = x;
	return 1;
}
int isempty(Queue Q) {
	return(Q->rear == Q->front);
}
int DeleteQ(Queue Q) {
	Q->front = (Q->front + 1) % Q->maxsize;
	return Q->Data[Q->front];
}
int isedge(MGraph graph, int a, int b) {
	return graph->G[a][b] < 20000 ? 1 : 0;
}
void BFS(MGraph graph, int N, int* visited, int s) {
	Queue Q;
	int v, w;
	Q = CreateQueue(N);
	
	visited[s] = 1;
	AddQ(Q, s);
	while (isempty(Q) == 0) {
		v = DeleteQ(Q);
		for (w = 1; w < graph->Nv + 1; w++) {/*遍历图中的每一个顶点*/
			if (visited[w] == 0 && isedge(graph, v, w)==1) {
				visited[w] = 1;
				AddQ(Q, w);
			}
		}
	}
}
void Floyd(MGraph graph,int weight[][101]) {
	int i, j, k;
	for (i = 1; i < graph->Nv + 1; i++) {
		for (j = 1; j < graph->Nv + 1; j++) {
			weight[i][j] = graph->G[i][j];
		}
	}
	for (k = 1; k < graph->Nv + 1; k++) {
		for (i = 1; i < graph->Nv + 1; i++) {
			for (j = 1; j < graph->Nv + 1; j++) {
				if (weight[i][k] + weight[k][j] < weight[i][j]) {
					weight[i][j] = weight[i][k] + weight[k][j];
				}
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值