哈利·波特的考试

此题考查有权多源图的最短路的算法

对于计算有权多源图的最短路径,有两种实现方法,一种是直接将单源最短路算法调用N遍,二是使用Floyd算法。

Floyd算法

1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
3,把所有顶点作为中间节点循环一遍,这是最外层的循环

具体如下:

  1. 把图用邻接矩阵G表示出来,如果从Vi到Vj有路可达,则G[i][j]=d,d表示该路的长度;否则G[i][j]=无穷大。同时G[i][i]需要设置为无穷大,以便后面比较
  2. 定义一个矩阵path用来记录所插入点的信息,path[i][j]表示从Vi到Vj需要经过的点,初始化path[i][j]=j。表示从i到j必须经过j
  3. 把各个顶点插入图中,比较插点后的距离与原来的距离,令G[i][j] = min( G[i][j], G[i][k]+G[k][j] ),如果G[i][j]的值变小,则path[i][j]=k。在G中包含有两点之间最短道路长度的信息,而在D中则包含了最短通路径的信息。
    比如,要寻找从V5到V1的路径。根据D,假如D(5,1)=3则说明从V5到V1经过V3,路径为{V5,V3,V1},如果D(5,3)=3,说明V5与V3直接相连,如果D(3,1)=1,说明V3与V1直接相连。

Floyd算法的时间复杂度为O(N3)


对于这个题目

题目:

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是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


从题目中,我们可以看到,每一个动物对应了一个顶点,而从一个动物变到另一个动物的咒语的长度对应了两个顶点之间的路径,本题要求找到最合适要带的动物,因此我们需要计算每一个动物变成别的动物的最短的咒语长度,然后找到这个其中最长的咒语长度,然后比较所有动物中最长的咒语长度中最短的一个就可以了。

因此该问题就是求多源最短路问题,同时从结果中找到最大最短路中最小的一个顶点。

对于本题,我们求得的最短路邻接表如下:每一行的最大元素表示选择这个动物最大代价,最后发现选择4号的最大代价最小,为70,输出结果

程序的基本框架为:

int main()
{
	Mgraph G = buildmgraph();//读入数据建立图
	FindAnimal(G);//根据原始图求得多源最短路图,并从中找到最合适的动物
	return 0;
}

而对于程序这两个步骤,继续分解为:

//建立图的函数
Mgraph creatmgraph(int nv);//先建立一个空的图
void insertedge(Mgraph M, Edge e);//定义插入边信息的函数
Mgraph buildmgraph();//构建原始的图
//找到最适合动物的函数
void Floyd(Mgraph M, Weight Dist[][MaxvertexNum]);//通过Floyd算法计算多源最短路径
Weight findmaxdist(Weight Dist[][MaxvertexNum], int i,int nv);//找到选择第i个动物的最大代价
void FindAnimal(Mgraph M);//根据图找到最佳动物

其中用到的数据类型以及要提前定义的变量有:

#define MaxvertexNum 100
#define Inf 10000 //最大顶点个数为100,每个边长度不超过100,因此总的路径也不会超过10000

typedef int Vertex;//定义顶点的数据类型
typedef int Weight;//定义边权重的数据类型

//定义边的数据类型
typedef struct Enode *ptrEnode;//定义边的指针
struct Enode//定义边的数据结构,包含两个顶点与边的权重
{
	Vertex V1, V2;
	Weight W;
};
typedef ptrEnode Edge;
//定义图的数据类型
typedef struct Gnode* ptrGnode;
struct Gnode
{
	int nv;//图的顶点个数
	int ne;//图的边的个数
	Weight G[MaxvertexNum][MaxvertexNum];//定义储存边信息的邻接矩阵
};
typedef ptrGnode Mgraph;

具体的每一个函数的实现代码如下:

Mgraph creatmgraph(int nv)//初始化一个图
{
	Vertex v,w;
	Mgraph G;
	G = (Mgraph)malloc(sizeof(struct Gnode));
	G->nv = nv;
	G->ne = 0;
	for (v = 0; v < G->nv; v++)
	{
		for (w = 0; w < G->nv; w++)
		{
			G->G[v][w] = Inf;//先将每一个点的到其他点的最短路径设为正无穷
		}
	}
	return G;
}

void insertedge(Mgraph M, Edge e)//将每一行的边信息插入邻接表
{
	//将读取的边插入表
	M->G[e->V1][e->V2] = e->W;
	M->G[e->V2][e->V1] = e->W;
	return;
}

Mgraph buildmgraph()
{
	Mgraph M;
	Edge e;
	int nv, i;
	scanf("%d", &nv);
	M = creatmgraph(nv);//初始化表
	scanf("%d", &M->ne);//读取边个数
	if (M->ne)
	{
		e = (Edge)malloc(sizeof(struct Enode));
		for (i = 0; i < M->ne; i++)
		{
			scanf("%d %d %d", &e->V1, &e->V2, &e->W);
			e->V1--; e->V2--;
			insertedge(M, e);
		}
	}
	return M;
}

void Floyd(Mgraph M, Weight Dist[][MaxvertexNum])//通过原图构建多源最短路图
{
	Vertex i, j, k;
	//初始化最短路图
	for (i = 0; i < M->nv; i++)
	{
		for (j = 0; j < M->nv; j++)
		{
			Dist[i][j] = M->G[i][j];
		}
	}
	//Floyd三重循环算法计算多源最短路,对i到j经历k的走法,如果更新k使得i到j距离更短,则更新
	for (k = 0; k < M->nv; k++)
	{
		for (j = 0; j < M->nv; j++)
		{
			for (i = 0; i < M->nv; i++)
			{
				Weight temp = Dist[i][k] + Dist[k][j];
				if (temp < Dist[i][j])
					Dist[i][j] = temp;
			}
		}
	}
	return;
}

Weight findmaxdist(Weight Dist[][MaxvertexNum], int i,int nv)//找到动物i到别的动物的最长路径
{
	Weight maxdist=0;
	Vertex j;
	for (j = 0; j < nv; j++)
	{
		if (i != j && Dist[i][j] > maxdist)
			maxdist = Dist[i][j];
	}
	return maxdist;
}

void FindAnimal(Mgraph M)//通过图M找到最小的动物
{
	Weight Dist[MaxvertexNum][MaxvertexNum], maxdist, mindist;
	Vertex animal, i;
	Floyd(M,Dist);//通过Floyd算法计算多源最短路径图
	//从计算完毕的Dist图中找到每一个动物到其他点的最短路中的最大路
	mindist = Inf;
	for (i = 0; i < M->nv; i++)
	{
		maxdist = findmaxdist(Dist, i,M->nv);//找到每一个动物的最大到别的动物的最大距离
		if (maxdist == Inf)
		{
			printf("0\n");
			return;
		}
		if (mindist > maxdist)//找到所有动物最大路径中最小的那个动物
		{
			mindist = maxdist;
			animal = i + 1;//记录该动物的编号
		}
	}
	printf("%d %d\n", animal, mindist);
}

数据结构的题拿C语言来写,可以进一步增加对数据结构的理解,虽然比较慢,但是还是比较有用的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值