这是图论的第一题,prim算法求最小生成树,做起来比较吃力。慢慢熟悉吧。
prim的思想是:分成两个集合,分别为访问过的点的集合、未访问过的点的集合。初始时刻,从图中任取一点(一般就是取0点,我猜的),加入访问过的点的集合,然后表示出该点到未访问的集合中各个点的距离。此后的过程为:从上面的距离中取出最小值的边,加入答案中,并将该边的另一个顶点放入到已经访问的集合,由于此时已经访问的集合的成员改变了,所以,该集合到未访问的集合的各个点的最小距离也要相应地更新。窃以为理解的关键是要有集合的思想,将已经访问和未访问视作两大集合,所取的边是连接两集合的最短的边。
详见代码:
/*************************************************************************
> File Name: main.cpp
> Author:Eagles
> Mail:None
> Created Time: 2018年09月02日 星期日 11时14分29秒
> Description:HDU1301
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 27
int map[N][N];
int dis[N];
bool vis[N];
int n;
const int INF=1<<30;
void init()
{
memset(map,0x1f,sizeof(map));
memset(vis,false,sizeof(vis));
memset(dis,0,sizeof(dis));
for (int i=1; i<n ;i++)
{
getchar();
char fir;
scanf("%c",&fir);
int num;
scanf("%d",&num);
while (num--)
{
char sec;
int val;
scanf("%c",&sec);
scanf("%c",&sec);
scanf("%d",&val);
map[fir-'A'][sec-'A']=val;
map[sec-'A'][fir-'A']=val;
}
}
for (int i=0; i<n ;i++)
dis[i]=map[0][i];//初始化dis是0到其他点的距离,0代表了已经访问的集合
}
void prim()
{
int sum=0;
vis[0]=true;
for (int i=0; i<n-1; i++)//这里要注意,只有n-1个点了
{
int mind=INF;
int tmp;
for (int j=0; j<n; j++)//寻找最小距离的边,以及边的另一个顶点
{
if (!vis[j]&&dis[j]<mind)
{
mind=dis[j];
tmp=j;
}
}
vis[tmp]=true;
sum+=mind;
for (int j=0; j<n; j++)//已经访问的集合改变了,所以到未访问集合各点的最小距离也要相应地更新
{
if (!vis[j]&&map[j][tmp]<dis[j])
dis[j]=map[j][tmp];
}
}
printf("%d\n",sum);
}
int main()
{
while (~scanf("%d",&n)&&n)
{
init();
prim();
}
return 0;
}