[kuangbin带你飞]专题六 最小生成树 A~E

本文详细介绍了使用Kruskal和Prim算法解决不同场景下的最小生成树问题,包括道路建设、网络构建等实际应用案例。

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

A - Jungle Roads

套模板  直接出

Kruskal

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int father[100];
int n,m;
struct point
{
    int u;
    int v;
    int w;
}a[5000];
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
    return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
    for(int i=0;i<=100;i++)
        father[i]=i;
}
int find(int x)  /*查找根节点*/
{
    if(father[x]==x)
        return x;
    return find(father[x]);
}
void merge(int p,int q)  /*合并两个集合*/
{
    int pp=find(p);
    int qq=find(q);
    if(pp!=qq)
    {
        if(pp<qq)
            father[qq]=pp;
        else
            father[pp]=qq;
    }
}
int kruskal()
{
    initial();  /*初始化*/
    int ans=0;
    sort(a+1,a+m+1,comp); /*排序*/
    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;
            merge(x,y); /*合并*/
        }
    }
    return ans;
}
int main()
{
    int i,sum;
    while(~scanf("%d",&n)&&n!=0)
    {
        int j =1;
        for(int i=1; i<n; i++)
        {
            int value;
            char ch[2];
            int s;
            int k,e;
            scanf("%s %d",&ch,&value);///   value代表后面的连接的边数,
            s=ch[0]-'A'+1;///起点
            while(value--)
            {
                scanf("%s %d",&ch,&k);
                j++;
                e=ch[0]-'A'+1;
                a[j].u=s;///起点
                a[j].v=e;///终点
                a[j].w=k;///距离
            }
        }
        m=j;
//        for(i=1;i<=m;i++)
//            scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
        sum=kruskal();
        printf("%d\n",sum);
    }
    return 0;
}

prim

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
	 next=-1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
int main(){
    while(cin>>n && n)
    {
        init();
        for(int i=1; i<n; i++){
            char u;
            int t1;
            int t;
            cin>>u>>t1;
            int tmp1 = u-'A'+1;
            while(t1 --)
            {
                cin>>u>>t;
                int tmp2 = u-'A'+1;
                map_1[tmp1][tmp2] = map_1[tmp2][tmp1]=t;
            }
        }
//        printf("**\n");
        begin_1 = 1;
        prime();
    }
    return 0;
}

B - Networking

 多重边,,prim选择最小的建图,,Kruskal直接都存起来排序就好了

这题C++提交一直wa,,改G++就过了  不知道为什么,,

Kruskal

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int father[100];
int n,m;
struct point
{
    int u;
    int v;
    int w;
}a[5000];
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
    return a1.w<a2.w;
}
void initial() /*并查集初始化*/
{
    for(int i=0;i<=100;i++)
        father[i]=i;
}
int find(int x)  /*查找根节点*/
{
    if(father[x]==x)
        return x;
    return find(father[x]);
}
void merge(int p,int q)  /*合并两个集合*/
{
    int pp=find(p);
    int qq=find(q);
    if(pp!=qq)
    {
        if(pp<qq)
            father[qq]=pp;
        else
            father[pp]=qq;
    }
}
int kruskal()
{
    initial();  /*初始化*/
    int ans=0;
    sort(a+1,a+m+1,comp); /*排序*/
    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;
            merge(x,y); /*合并*/
        }
    }
    return ans;
}
int main()
{
    int i,sum;
    while(~scanf("%d",&n)&&n)
    {
        cin>>m;
        for(int i=1; i<=m; i++)
        {
            int u,v,w;
            cin>>u>>v>>w;
            a[i].u = u;
            a[i].v = v;
            a[i].w = w;
        }

        sum=kruskal();
        printf("%d\n",sum);
    }
    return 0;
}

prim

C++又可以过,,???是我板子的问题吗///迷。。

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
	 next=-1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
int main(){
    while(cin>>n && n)
    {
        init();
        int m;
        cin>>m;
        for(int i=1; i<=m; i++){
            int u,v,w;
            cin>>u>>v>>w;
            map_1[u][v] = map_1[v][u] = min(map_1[u][v],w);
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

C - Building a Space Station

 给我们n个点的坐标(x,y,z)和半径r  

建图:两个for循环,求出两个球球面的距离。先算出两个球心之间的距离,若该距离<两个半径之和,则两个球面的距离=球心距离-两半径之和;否则,两个球面必定有交点,距离赋值为0

Kruskal

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
using namespace std;
const int fa_n = 200+5;
const int maxn = 10050;
int father[fa_n];
int n,m;

double x[maxn];
double y[maxn];
double z[maxn];
double r[maxn];
struct point
{
    int u;
    int v;
    double w;
}a[5000];
int tol = 1;
void addedge(int u,int v,double w)
{
	a[++tol].u=u;
	a[tol].v=v;
	a[tol].w=w;
}
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
    return a1.w<a2.w;
}

void initial() /*并查集初始化*/
{
    for(int i=0;i<=fa_n;i++)
        father[i]=i;
}
int find(int x)  /*查找根节点*/
{
    if(father[x]==x)
        return x;
    return find(father[x]);
}
void merge(int p,int q)  /*合并两个集合*/
{
    int pp=find(p);
    int qq=find(q);
    if(pp!=qq)
    {
        if(pp<qq)
            father[qq]=pp;
        else
            father[pp]=qq;
    }
}
double kruskal()
{
    initial();  /*初始化*/
    double ans=0;
    sort(a+1,a+tol+1,comp); /*排序*/
    int cnt = 0;
    for(int i=1;i<=tol;i++)
    {
        int x=find(a[i].u);
        int y=find(a[i].v);
        if(x!=y)  /*两端点不属于同一集合*/
        {
            ans+=a[i].w;
            merge(x,y); /*合并*/
            cnt ++;
        }
        if(cnt == n-1)
        {
            break;
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {

        tol = 0;//边的数目
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%lf",&x[i],&y[i],&z[i],&r[i]);
            for(int j=i-1; j>=1; j--)
            {
                double dist=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]))-r[i]-r[j];
				if (dist<=0) addedge(i,j,0);
				else addedge(i,j,dist);
            }
        }

        double sum=kruskal();
        printf("%.3f\n",sum);
    }
    return 0;
}

D - Constructing Roads

 给你个图,,已经建好了一些边,,求最小生成树,,prim把建好的边直接为0,,Kruskal先合并已经建好的边

Kruskal

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int fa_n = 100+5;
int father[fa_n];
int ma[1005][1005];
int n,m;
struct point
{
    int u;
    int v;
    int w;
}a[5000];
int tol = 1;
void addedge(int u,int v,int w)
{
	a[++tol].u=u;
	a[tol].v=v;
	a[tol].w=w;
}
bool comp(point a1,point a2) /*按权值从小到大排序*/
{
    return a1.w<a2.w;
}

void initial() /*并查集初始化*/
{
    for(int i=0;i<=fa_n;i++)
        father[i]=i;
}
int find(int x)  /*查找根节点*/
{
    if(father[x]==x)
        return x;
    return find(father[x]);
}
void merge(int p,int q)  /*合并两个集合*/
{
    int pp=find(p);
    int qq=find(q);
    if(pp!=qq)
    {
        if(pp<qq)
            father[qq]=pp;
        else
            father[pp]=qq;
    }
}
int cnt = 0;
int kruskal()
{
    int ans=0;
    sort(a+1,a+tol+1,comp); /*排序*/
    for(int i=1;i<=tol;i++)
    {
        int x=find(a[i].u);
        int y=find(a[i].v);
        if(x!=y)  /*两端点不属于同一集合*/
        {
            ans+=a[i].w;
            merge(x,y); /*合并*/
            cnt ++;
        }
        if(cnt == n-1)
        {
            break;
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                cin>>ma[i][j];
            }
        }
        tol = 0;//边的数目
        cnt = 0;
        initial();  /*初始化*/
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=i-1; j++)
            {
                    addedge(i,j,ma[i][j]);
            }
        }
        int m;
        cin>>m;
        for(int i=1; i<=m; i++)
        {
            int x,y;
            cin>>x>>y;
            int u=find(x);
            int v=find(y);
            if(u!=v)  /*两端点不属于同一集合*/
            {
                merge(x,y); /*合并*/
            }
        }
//        cout<<cnt<<endl;
        int sum=kruskal();
        printf("%d\n",sum);
    }
return 0;
}

prim

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) a[i][j]=0;
        else a[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int a[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=a[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>a[next][j])
            lowdis[j]=a[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) a[i][j]=0;
            else a[i][j]=INF;
    }
}
int main(){
    while(cin>>n && n)
    {
        init();
        char c1;
        int t;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        int q;
        cin>>q;
        while(q --)
        {
            int x,y;
            cin>>x>>y;
            a[x][y] = a[y][x] = 0;
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

E - QS Network

 建图:给你的n*n矩阵不是直接的花费,而是边花费,总花费=边花费+两个端点的花费

prim

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) a[i][j]=0;
        else a[i][j]=INF;
}
*/
const int N = 1000+10;
int tree[N];
int b[N];
int lowdis[N];
int a[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=a[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>a[next][j])
            lowdis[j]=a[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) a[i][j]=0;
            else a[i][j]=INF;
    }
}
int main(){
    int t;
    cin>>t;
    while(t --)
    {
        cin>>n;
        init();
        for(int i=1; i<=n; i++)
        {
            cin>>b[i];
        }
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&a[i][j]);
                if(i!=j)
                {
                    a[i][j] = a[j][i] =a[i][j]+b[i]+b[j];
                }
            }
        }
//        printf("**\n");
        begin_1 = 1;
        prime();
    }
    return 0;
}
内容概要:本文详细探讨了基于阻尼连续可调减振器(CDC)的半主动悬架系统的控制策略。首先建立了CDC减振器的动力学模型,验证了其阻尼特性,并通过实验确认了模型的准确性。接着,搭建了1/4车辆悬架模型,分析了不同阻尼系数对悬架性能的影响。随后,引入了PID、自适应模糊PID和模糊-PID并联三种控制策略,通过仿真比较它们的性能提升效果。研究表明,模糊-PID并联控制能最优地提升悬架综合性能,在平顺性和稳定性间取得最佳平衡。此外,还深入分析了CDC减振器的特性,优化了控制策略,并进行了系统级验证。 适用人群:从事汽车工程、机械工程及相关领域的研究人员和技术人员,尤其是对车辆悬架系统和控制策略感兴趣的读者。 使用场景及目标:①适用于研究和开发基于CDC减振器的半主动悬架系统的工程师;②帮助理解不同控制策略(如PID、模糊PID、模糊-PID并联)在悬架系统中的应用及其性能差异;③为优化车辆行驶舒适性和稳定性提供理论依据和技术支持。 其他说明:本文不仅提供了详细的数学模型和仿真代码,还通过实验数据验证了模型的准确性。对于希望深入了解CDC减振器工作原理及其控制策略的读者来说,本文是一份极具价值的参考资料。同时,文中还介绍了多种控制策略的具体实现方法及其优缺点,为后续的研究和实际应用提供了有益的借鉴。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值