最小生成树prim算法实现及1233解题思路

今天写最下生成树prime算法实现及1233的解题思路

  最小生成树prim算法。
  prim算法的原理和最短路的原理非常相似,①  要建立一个二维数组保存数据;②  找到一个点(这个随意,因为要经过所有的点,所以从哪个点开始并不重要),并把最小的权值(距离)保存进数组dis[ ]里;③  从二维数组中找到与上一个点相连的权值最小的点, 并与上一点的权值相比较,权值比上一个点的权值小就保存入dis[ ]中;④  用循环执行③步骤n-1(n为最小生成树中点的个数)次。


  hdu 1233 的解题思路。
  先附上原题:

还是畅通工程

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 24052    Accepted Submission(s): 10684


Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
 

Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
 

Output
对每个测试用例,在1行里输出最小的公路总长度。
 

Sample Input
   
   
3 1 2 1 1 3 2 2 3 4 4 1 2 1 1 3 4 1 4 1 2 3 3 2 4 2 3 4 5 0
 

Sample Output
   
   
3 5


  首先是数据的输入及数组的处理,要保存数据就必须先创建二维数组保存数据(要注意的是从a地到a地的权值为0),这个没难度,直接附代码!
const int maxx = 102;
int map[maxx][maxx];

int main()
{
    int n;
    int m;
    while(scanf("%d",&n)&&n)
    {
        m = ((n-1)*n)/2;
        int a, b, c;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(i==j) map[i][j] = 0;
                else map[i][j] = inf;
            }
        }
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            if(map[a][b]>c)
            {
                map[a][b] = map[b][a] = c;
            }
        }
        int d = prim(n);
        printf("%d\n",d);
    }
    return 0;
}

  然后代码中的prim即核心内容,接下来是最想生成树prim算法在hdu 1233的实现。
  因为题目要求是输出最的小公路长度,所以我们在prim中只要返回总长度就行了,于是我们就定义sum来记录公路的总长度,因为要标记点是否被访问过,所以,我们定义bool vis[ ]来记录点是否被访问过,当然我们也要定义一个minn来保存最小的权值并把它加入到sum中!
  最后一些思路实现就写在代码的注释里了!
  代码:
const int inf = 0xfffff;
const int maxx = 102;     
int dis[maxx];
bool vis[maxx];
int prim(int n)
{
    int sum=0;                        ///sum记得要初始化为0;
    memset(vis,0,sizeof(vis));        ///标记是否被访问过要记得初始化为0;
    for(int i=1; i<=n; i++)
    {
        dis[i] = map[1][i];           ///把与点①相连的点的权值放入dis[ ]中 ;
    }
    vis[1] = 1;                       ///标记点①已经被访问过;
    for(int i=1; i<n; i++)
    {
        int minn = inf, k;            ///定义最小权值为最大值,方便更新minn;
        for(int j=1; j<=n; j++)
        {
            if(!vis[j]&&minn>dis[j])  ///判断点是否被访问过;
            {
                minn = dis[j];        ///记录最小权值;
                k = j;                ///记录最小权值的点;
            }
        }
        sum = sum + minn;             /// 把最小的权值加入sum中;
        vis[k] = 1;                   ///标记最小权值的点为已访问过;
        for(int j=1; j<=n; j++)
        {
            if(dis[j]>map[k][j])      ///判断大小,并决定是否要更新最小生成树;
                dis[j] = map[k][j];
        }
    }
    return sum;
}

  其中最重要的两个语句是:
if(!vis[j]&&minn>dis[j])
  和
if(dis[j]>map[k][j])   dis[j] = map[k][j];

  以上!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值