数据结构-图结构-最小生成树问题-公路村村通(Prime算法和Kruskal算法)

题目:
现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:
输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:
输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例:

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12
  • 这题主要考查最小生成树算法(Prime算法和Kruskal算法)

解决代码

#include<stdio.h>
#include<stdlib.h>
#define MAXN 1001  //从1开始
#define INF 100000
int Map[MAXN][MAXN],Cost[MAXN],N,M;
int parent[MAXN];  //用于并查集存放父亲下标
typedef struct Edge  //边节点
{
   int V;
   int W;
   int Cost;
}Edge;
Edge *E;
void CreateGraph(int n, int e)  //创建初始化图
{
   int v,w,i;
   for(v=1;v<=n;v++)
   {
       Cost[v]=0;    //存放各顶点到最小生成树的距离(价格)
       for(w=1;w<=n;w++) 
       {
           if(v==w)
              Map[v][w]=0;  //自己到自己不要钱
           else 
              Map[v][w]=INF;
       }
   }
   E=(Edge*)malloc(sizeof(struct Edge)*e);  //开一个边的动态数组
   for(i=0;i<e;i++)
   {
       scanf("%d %d %d",&E[i].V,&E[i].W,&E[i].Cost); //赋值边
       Map[E[i].V][E[i].W]=E[i].Cost;  //邻接矩阵权重赋值
       Map[E[i].W][E[i].V]=E[i].Cost;
   }
}
/*************************************Prime算法******************************************/
int FindMinCost()  //找最小价格
{
    int i,MinCost,MinCostPosition;
    MinCost=INF;
    MinCostPosition=0;
    for(i=1;i<=N;i++)
    {
       if(Cost[i] && Cost[i]<MinCost)  //如果价格不等于0,且更小
       {
           MinCost=Cost[i];
           MinCostPosition=i;
       }
    }
    return MinCostPosition;
}
int Prime()
{
    int i,GrossCost=0,MinCost,Count=0;
    for(i=1;i<=N;i++)Cost[i]=Map[1][i];   //从第1个村出发到各村的价格
    while(1)
    {
        MinCost=FindMinCost();
        if(MinCost==0)break;      //找不到最小的价格
        else  //找到最小价格,最小生成树长大
        {
            GrossCost+=Cost[MinCost];  //总价格更新
            Count++;  //计数器更新
            Cost[MinCost]=0;
        for(i=2;i<=N;i++)
        {
            if(Cost[i] && Cost[i]>Map[MinCost][i])  //如果价格不等于0,且各还没收入顶点到更新后的最小生成树距离更小
            {
               Cost[i]=Map[MinCost][i];  //那么更新距离
            }
        }
        }
    }
    if(Count<N-1)return -1;
    else return GrossCost;
}
/*************************************Kruskal算法******************************************/
void Shell_Sort()  //希尔排序
{
    int Si, D, P, i;
    Edge Tmp;
    int Sedgewick[] = {3905,2161,929, 505, 209, 109, 41, 19, 5, 1, 0};
    for ( Si=0; Sedgewick[Si]>=M; Si++ ) ; 
    for ( D=Sedgewick[Si]; D>0; D=Sedgewick[++Si] )
        for ( P=D; P<M; P++ )  //插入排序
        {
            Tmp = E[P];
            for ( i=P; i>=D && E[i-D].Cost >Tmp.Cost ; i-=D )
                E[i] = E[i-D] ;
            E[i] = Tmp;
        }
}
int FindParent(int v)  //查找集合
{
    if(parent[v]==v) return v;
    else return FindParent(parent[v]);
}
int Associate(int v,int w)  //合并集合
{
    int root1,root2;
    root1=FindParent(v);  //找到父亲
    root2=FindParent(w);  //找到父亲
    if(root1!=root2)  //如果父亲不一样
    {
       parent[root2]=root1;  //合并两个集合
       return 1;
    }
    return 0;
}
int Kruskal()
{
    int i,GrossCost=0,Count=0;
    Shell_Sort();  //希尔排序边集
    for(i=1;i<=N;i++)parent[i]=i;   //每个顶点一开始自己就是自己的父亲
    for(i=0;i<M;i++)
    {
       if(Associate(FindParent(E[i].V ),FindParent(E[i].W )))
       {
           Count++;  //边数+1
           GrossCost+=E[i].Cost;  //总价格更新
       }
       if(Count==N-1)break;  //有N-1条边了结束
 }
    if(Count<N-1) return -1;  //边数不够
    else return GrossCost;
}
int main()
{
    scanf("%d%d",&N,&M);
    CreateGraph(N,M);
    //printf("%d\n",Prime());
    printf("%d\n",Kruskal());
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值