poj1258分析由题意分析得该题目为最小生成树的裸题
首先介绍下最小生成树的相关概念:
带权图:边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权。
最小生成树(MST):权值最小的生成树。
生成树和最小生成树的应用:要连通n个城市需要n-1条边线路。可以把边上的权值解释为线路的造价。则最小生成树表示使其造价最小的生成树。
所以,接下来介绍下求最小生成树的Prim算法如下:
(1)普利姆算法(prim)求最小生成树(MST)
下图是一个简单的带权图:
首先任意选择一个结点:
在这选择v4为第一个结点,v4相邻的路径有两个,选择最小的一个v3构成最小生成树的第一个路径,如下:
接下来,从v3结点选择相邻的最短路径,一次,进行,v4->v3->v1->v2->v6->v5,结果如下:
所以该题如下:`#include
#include <string.h>
#include <stdio.h>
/infinity
//表示总路长最大值
//INF ≥ 单条路径最大值(100,000) × (MAXTOWNN(100)- 1)
#define INF 10000000
#define TRUE 1
#define FALSE 0
//maximum number of towns
//城镇数量的最大值
#define maxtownn 101
typedef char BOOL;
int d[maxtownn][maxtownn]; //i到j的距离
BOOL v[maxtownn]; /[i]表示i号镇是否被纳入集合中,即have been visited
int dp[maxtownn]; //dp[j]表示动态规划记录当前集合外的点j到集合内点的最小距离
int prim(int n) //prim求最小生成树
{
int i, j;
int min, minj;
int ans;
//初始化
dp[1] = 0;
for ( i = 2; i <= n; i++ )
dp[i] = d[1][i];
memset( v+1, FALSE, n * sizeof(BOOL));
v[1] = TRUE;
//将n个点全部纳入集合后就代表算法成功结束
for ( ans = 0, i = 2; i <= n; i++ )
{
//找出当前集合外到集合内点最短距离以及该集合外的点
for ( min = INF, minj = 0, j = 2; j <= n; j++ )
if ( !v[j] && dp[j] < min )
{
min = dp[j];
minj = j;
}
if (!minj) //集合外的点到集合内的点都不可达,表示无最小生成树
return INF; //那么答案自然就是无穷大了
v[minj]= TRUE;
ans+= min;
for ( j = 2; j <= n; j++ )
if ( !v[j] && d[minj][j] < dp[j] )
dp[j] = d[minj][j];
}
return ans;
}
int main()
{
int n;
int i, j;
while ( ~scanf("%d", &n) )
{
for ( i = 1; i <= n; i++ )
for ( j = 1; j <= n; j++ )
scanf("%d", &d[i][j]);
printf("%d\n", prim(n));
}
return 0;
}