数据结构_习题8.4 畅通工程之最低成本建设问题_习题8.5 畅通工程之局部最小花费问题_Kruskal+并查集+qsort

文章是关于使用Kruskal算法解决最小生成树问题的C++代码实现,通过并查集进行集合合并,并采用qsort进行排序。程序包括两部分,第一部分处理一般情况,第二部分考虑了额外的状态变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 题目分析:最小生成树问题,解法采取了Kruskal算法,利用qsort和并查集实现。8.5在8.4的基础上稍作调整即可。
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;

typedef struct path{
    int val;
    int town1,town2;
}path;
typedef path *pap;

int cmp(const void *a,const void *b){
    pap p1=*(pap *)a,p2=*(pap *)b;
    return p1->val - p2->val;
}

int townG[1001];            //记录Group
int findG(int id){              //根或裸节点
    if(townG[id]<=0) return id; 
    else return townG[id]=findG(townG[id]); //路径压缩
}
void unionG(int id1,int id2){   //仅处理根或裸节点
    townG[id1]+=townG[id2];
    townG[id2]=id1;
}

int main()
{
    int n,m;
    pap P[3000];
    scanf("%d %d",&n,&m);
    for (int i = 0; i < m; i++){
        P[i]=(pap)malloc(sizeof(path));
        scanf("%d %d %d",&P[i]->town1,&P[i]->town2,&P[i]->val);
    }
    qsort(P,m,sizeof(pap),cmp);

    memset(townG,-1,sizeof(townG));
    int pi=0,cost=0,useP=0;
    while (pi<m && useP!=n-1)
    {
        pap tmp=P[pi++];
        int id1=findG(tmp->town1), id2=findG(tmp->town2);//均需转换成根节点(townG[id]小于0,或等于0)。
        if(id1!=-1 && id1==id2) continue;//非裸,且同一个集合
        
        if(townG[id1]<townG[id2]) unionG(id1,id2);
        else unionG(id2,id1);
        cost+=tmp->val,useP++;
    }
    if(useP==n-1) printf("%d",cost);
    else printf("Impossible");

    return 0;
}
#include<iostream>
#include<stdlib.h>
#include<string.h>
using namespace std;

typedef struct path{
    int val;
    int town1,town2;
    int state;
}path;
typedef path *pap;

int cmp(const void *a,const void *b){
    pap p1=*(pap *)a,p2=*(pap *)b;
    return p1->val - p2->val;
}

int townG[101];             //记录Group
int findG(int id){              //找根或裸节点
    if(townG[id]<0) return id; 
    else return townG[id]=findG(townG[id]); //路径压缩
}
void unionG(int id1,int id2){   //处理根或裸节点
    townG[id1]+=townG[id2];
    townG[id2]=id1;
}

int pi=0,cost=0,useP=0;       //通过pi使用P,成本记录,联通的路径数目
int updateG(int id1,int id2); //并查集,同个集合返0,新联通返1

int main()
{
    int n;
    pap P[5000];
    scanf("%d",&n);
    int pn=(n*(n-1))/2;
    memset(townG,-1,sizeof(townG));
    for (int i = 0; i < pn; i++){
        P[i]=(pap)malloc(sizeof(path));
        scanf("%d %d %d %d",&P[i]->town1,&P[i]->town2,&P[i]->val,&P[i]->state);
        if(P[i]->state==1) updateG(P[i]->town1,P[i]->town2);
    }
    qsort(P,pn,sizeof(pap),cmp);

    while (pi<pn && useP!=n-1)
    {
        pap tmp=P[pi++];

        if(tmp->state==0) //可能需要联通
        {   
            int flag=updateG(tmp->town1,tmp->town2);
            if(flag==1) cost+=tmp->val;
        }
    }
    if(useP==n-1) printf("%d",cost);
    else printf("Impossible");

    return 0;
}
int updateG(int id1,int id2)
{
    id1 = findG(id1), id2 = findG(id2);
    if (id1 != -1 && id1 == id2) return 0; //非裸,且同一个集合

    useP++;                                //有效路径+1
    if (townG[id1] < townG[id2]) unionG(id1, id2);
    else unionG(id2, id1);

    return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值