1. 程式人生 > >問題 1705: 演算法7-9:最小生成樹

問題 1705: 演算法7-9:最小生成樹

http://www.dotcpp.com/oj/problem1705.html

題目描述

最小生成樹問題是實際生產生活中十分重要的一類問題。假設需要在n個城市之間建立通訊聯絡網,則連通n個城市只需要n-1條線路。這時,自然需要考慮這樣一個問題,即如何在最節省經費的前提下建立這個通訊網。

可以用連通網來表示n個城市以及n個城市之間可能設定的通訊線路,其中網的頂點表示城市,邊表示兩個城市之間的線路,賦於邊的權值表示相應的代價。對於n個頂點的連通網可以建立許多不同的生成樹,每一棵生成樹都可以是一個通訊網。現在,需要選擇一棵生成樹,使總的耗費最小。這個問題就是構造連通網的最小代價生成樹,簡稱最小生成樹。一棵生成樹的代價就是樹上各邊的代價之和。

而在常用的最小生成樹構造演算法中,普里姆(Prim)演算法是一種非常常用的演算法。以下是其演算法的大致結構:

在本題中,讀入一個無向圖的鄰接矩陣(即陣列表示),建立無向圖並按照以上描述中的演算法建立最小生成樹,並輸出最小生成樹的代價。

 

輸入

輸入的第一行包含一個正整數n,表示圖中共有n個頂點。其中n不超過50。

以後的n行中每行有n個用空格隔開的整數,對於第i行的第j個整數,如果不為0,則表示第i個頂點和第j個頂點有直接連線且代價為相應的值,0表示沒有直接連線。當i和j相等的時候,保證對應的整數為0。

輸入保證鄰接矩陣為對稱矩陣,即輸入的圖一定是無向圖,且保證圖中只有一個連通分量。

輸出

只有一個整數,即最小生成樹的總代價。請注意行尾輸出換行。

樣例輸入

4
0 2 4 0
2 0 3 5
4 3 0 1
0 5 1 0

樣例輸出

6

提示

在本題中,需要掌握圖的深度優先遍歷的方法,並需要掌握無向圖的連通性問題的本質。通過求出無向圖的連通分量和對應的生成樹,應該能夠對圖的連通性建立更加直觀和清晰的概念。

 

Prim演算法

#include<stdio.h>
#define N 120
int e[N][N],dis[N],book[N];
int main()
{
	int i,j,k,m,n,min,count=0,sum=0,inf=99999999;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)	
			if(i==j)
				e[i][j]=0;
			else
				e[i][j]=inf;
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
		{
			scanf("%d",&e[i][j]);
			//e[j][i]=e[i][j];
			if(i!=j&&e[i][j]==0)
				e[i][j]=e[j][i]=inf;
		}
	
	for(i=1;i<=n;i++)
		dis[i]=e[1][i];
	book[1]=1;
	count++;
	while(count<n)
	{
		min=inf;
		for(i=1;i<=n;i++)
		{
			if(book[i]==0&&dis[i]<min)
			{
				min=dis[i];
				j=i;
			}
		}
		book[j]=1;
		count++;
		sum=sum+dis[j];
		for(k=1;k<=n;k++)
		{
			if(book[k]==0&&dis[k]>e[j][k])
			dis[k]=e[j][k];
		}
	}
	printf("%d\n",sum);
	return 0;
}