1. 程式人生 > >資料結構圖的最短路徑問題

資料結構圖的最短路徑問題

07-圖4 哈利·波特的考試 (25 point(s))

哈利·波特要考試了,他需要你的幫助。這門課學的是用魔咒將一種動物變成另一種動物的本事。例如將貓變成老鼠的魔咒是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

 

首先定義圖和邊,用鄰接矩陣表示

#define MaxVertexNum 100   // 最大邊數
#define INFINITY 65535
typedef int WeightType;
typedef struct GNode *PtrToNode;
typedef PtrToNode MGraph;
struct GNode
{
	int Nv;   // 頂點數
	int Ne;   // 邊數
	WeightType G[MaxVertexNum][MaxVertexNum];  // 鄰接矩陣

};

typedef int Vertex;
typedef struct ENode *PtrToENode;
typedef PtrToENode Edge;
struct ENode
{
	Vertex V1, V2;
	WeightType Weight;
	
};

建立一個無向圖所需的函式

MGraph CreateGraph(int VertexNum)
{
	/* 初始化一個有VertexNum個頂點但沒有邊的圖*/
	Vertex V, W;
	MGraph Graph;
	Graph = (MGraph)malloc(sizeof(struct GNode));
	Graph->Nv = VertexNum;
	Graph->Ne = 0;
	for (V = 0; V < Graph->Nv; V++)
	{
		for (W = 0; W < Graph->Nv; W++)
		{
			Graph->G[V][W] = INFINITY;
		}
	}
	return Graph;
}

void InserEdge(MGraph Graph, Edge E)
{
	Graph->G[E->V1][E->V2] = E->Weight;
	Graph->G[E->V2][E->V1] = E->Weight;
}

讀入資料,建立圖

MGraph BuildGraph()
{
	MGraph Graph;
	Edge E;
	int Nv;

	scanf("%d", &Nv);            // 讀入頂點的個數
	Graph = CreateGraph(Nv);

	scanf("%d", &(Graph->Ne));   // 讀入邊數

	if (Graph->Ne != 0)
	{
		E = (Edge)malloc(sizeof(struct ENode));
		for (int i = 0; i < Graph->Ne; i++)
		{
			scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
			E->V1--; E->V2--;       // 題目的編號輸入從1開始
			InserEdge(Graph, E);
		}
	}

	return Graph;
}

最短路徑Floyd演算法

void Floyd(MGraph Graph, WeightType D[][MaxVertexNum])
{
	// 初始化
	for (int i = 0; i < Graph->Nv; i++)
	{
		for (int j = 0; j < Graph->Nv; j++)
		{
			D[i][j] = Graph->G[i][j];
		}
	}

	for (int k = 0; k < Graph->Nv; k++)
	{
		for (int i = 0; i < Graph->Nv; i++)
		{
			for (int 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];
				}
			}
		}
	}
}
WeightType FindMaxDist(WeightType D[][MaxVertexNum], Vertex i, int N)
{
	/* 根據路徑矩陣D找出N個頂點中,頂點i的最大路徑 */

	WeightType MaxDist = 0;
	for (int 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;

	Floyd(Graph, D);

	MinDist = INFINITY;

	for (int i = 0; i < Graph->Nv; i++)
	{
		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);
}

主函式
 

int main()
{
	MGraph G = BuildGraph();
	FindAnimal(G);
	return 0;
}