最小生成树模板题POJ - 1287-prim+kruskal

POJ - 1287超级模板题

大概意思就是点的编号从1到N,会给你m条边,可能两个点之间有多条边这种情况,求最小生成树总长度?

这题就不解释了,总结就算,prim是类似dijkstra,从第一个点出发,每次走这个点没走过的最小边权值,这样不断找下去就可以找出,本质就是贪心算法

而kruskal是利用并查集,先按照边权值大小排序,然后从小的边开始往里面添加边,利用并查集判断是否在一个联通分量里面(就是是否相连)如果不相

连就建立边,从而建图,注意,节点编号如果是从1->n,那么相应初始化就应该从1->N;

prim版本:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<string.h>
 4 using namespace std;
 5 const int INF = 0x3f3f3f3f;
 6 const int maxx = 1e2+7;
 7 int cost[maxx][maxx];
 8 int mincost[maxx];
 9 bool used[maxx];
10 int v;
11 int m,n;
12 int prim(){
13   for (int i=1;i<=n;i++){
14     mincost[i]=INF;
15     used[i]=false;
16   }
17  mincost[1]=0;//这里的数组的编号,代表我最开始建图的点
18   int res=0;
19   while(true){
20     int v = -1;
21     for (int u=1;u<=n;u++){ //枚举边找到这个点的下一个边权值最小的点
22         if (!used[u] && (v==-1 || mincost[u] < mincost[v])) v=u; 
23     }
24     if (v == -1)break;//没有的话就返回,无法建图
25     used[v]=true;//顶点加入
26     res+=mincost[v];
27     for (int u=1;u<=n;u++){
28         mincost[u] = min(mincost[u],cost[v][u]);//???
29     }
30   }
31   return res;
32 }
33 int main(){
34   int tmp1,tmp2,tmp3;
35    while(scanf("%d",&n) && n){
36       scanf("%d",&m);
37       if (m==0){
38         cout<<"0"<<endl;
39         continue;
40       }
41      for (int i=1;i<=n;i++){
42         for(int j=1;j<=n;j++){
43             if (i==j)cost[i][j]=0;
44             else cost[i][j]=INF;
45         }
46      }
47      for (int i=1;i<=m;i++){
48         scanf("%d%d%d",&tmp1,&tmp2,&tmp3);
49         if (tmp3<cost[tmp1][tmp2])cost[tmp1][tmp2]=cost[tmp2][tmp1]=tmp3;//更新成最短边
50      }
51     cout<<prim()<<endl;
52    }
53   return 0;
54 }

Kruskal

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct node{
  int u,v,w;
}a[10050];
int p[10055];
int r[10055];
int n,m;
int find(int x){return p[x] == x ? x : p[x] = find(p[x]);}//找根节点
int cmp(node x,node y)
{
    return x.w<y.w;//按照边权值排序
}
int Kruskal(){
        int ans=0;
        int num=0;
        for (int i=1; i<=n; i++)p[i]=i;
        sort(a+1,a+1+m,cmp);
        for (int i=1; i<=m; i++)
        {
            int x=find(a[i].u);//出发点的根节点
            int y=find(a[i].v);//到达点的根节点
            if (x!=y)//不是一个根节点
            {
                ans+=a[i].w;//连接
                p[x]=y;//y是x的父亲节点
                num++;//建立好了n-1条边
            }
            if (num==n-1){
                break;
            }
        }
    return ans;
}
int main()
{
    int tmp1,tmp2,tmp3;
    while(~scanf("%d",&n))
    {
        if (n==0)break;
        scanf("%d",&m);
        for (int i=1; i<=m; i++)
        {
            scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
        }
        printf("%d\n",Kruskal());
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/bluefly-hrbust/p/9410730.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值