• 用prim和kruskal算法求最小生成树问题


    目录

    1.最短网络

    2.局域网

    3.繁忙的都市

    4.联络员

    5.连接格点


    prim算法就类似与dijkstra算法从1号点到其他点的最短距离

    kruskal算法是先按照边权排序,假如这条边的两个点不连通就加上这条边,假如连通了就跳过

    1.最短网络

    1140. 最短网络 - AcWing题库

    1. #include
    2. using namespace std;
    3. const int N=110;
    4. int w[N][N];
    5. bool st[N];
    6. int dist[N];
    7. int n,res=0;
    8. void prim()
    9. {
    10. memset(dist,0x3f,sizeof dist);
    11. dist[1]=0;//初始化第一个点到自己的距离为0
    12. for(int i=1;i<=n;i++)//找剩下的n个点与第一起点的距离,就像dijkstra一样
    13. {
    14. int t=-1;
    15. for(int j=1;j<=n;j++)
    16. if(!st[j]&&(t==-1||dist[t]>dist[j]))//找不在连通块且距离最小的点
    17. t=j;
    18. st[t]=true;//标记这个点在连通块内
    19. res+=dist[t];
    20. for(int j=1;j<=n;j++) dist[j]=min(dist[j],w[t][j]);//用该点更新其他点的最短距离
    21. }
    22. }
    23. int main()
    24. {
    25. cin>>n;
    26. for(int i=1;i<=n;i++)
    27. for(int j=1;j<=n;j++)
    28. cin>>w[i][j];
    29. prim();
    30. cout<
    31. return 0;
    32. }

    2.局域网

    信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    相当于一个图中求最小生成树的问题

    prim解决

    1. #include
    2. using namespace std;
    3. const int N=110;
    4. int w[N][N];
    5. bool st[N];
    6. int dist[N];
    7. int n,res=0,m;
    8. void prim()
    9. {
    10. memset(dist,0x3f,sizeof dist);
    11. dist[1]=0;//初始化第一个点到自己的距离为0
    12. for(int i=1;i<=n;i++)//找剩下的n个点与第一起点的距离,就像dijkstra一样
    13. {
    14. int t=-1;
    15. for(int j=1;j<=n;j++)
    16. if(!st[j]&&(t==-1||dist[t]>dist[j]))//找不在连通块且距离最小的点
    17. t=j;
    18. st[t]=true;//标记这个点在连通块内
    19. res+=dist[t];
    20. for(int j=1;j<=n;j++) dist[j]=min(dist[j],w[t][j]);//用该点更新其他点的最短距离
    21. }
    22. }
    23. int main()
    24. {
    25. int ans=0;
    26. cin>>n>>m;
    27. memset(w,0x3f,sizeof w);
    28. while(m--)
    29. {
    30. int a,b,c;
    31. cin>>a>>b>>c;
    32. w[a][b]=w[b][a]=min(w[a][b],c);
    33. ans+=w[a][b];//记录所有网线的答案
    34. }
    35. prim();
    36. cout<//输出总的减最小生成数的
    37. return 0;
    38. }

    kruskal解决

    1. #include
    2. using namespace std;
    3. const int N=110,M=N*N;
    4. int n,m;
    5. struct Edge
    6. {
    7. int a,b,w;
    8. bool operator < (const Edge&t)const//重载小于号,待会排序就按照w排序
    9. {
    10. return w
    11. }
    12. }e[M];//结构体存数
    13. int p[N];
    14. int find(int x)//并查集
    15. {
    16. if(p[x]!=x) p[x]=find(p[x]);
    17. return p[x];
    18. }
    19. int main()
    20. {
    21. int ans=0;
    22. cin>>n>>m;
    23. for(int i=1;i<=n;i++) p[i]=i;//并查集初始化
    24. for(int i=0;i
    25. {
    26. int a,b,w;
    27. cin>>a>>b>>w;
    28. e[i]={a,b,w};
    29. }
    30. sort(e,e+m);//先排序
    31. for(int i=0;i
    32. {
    33. int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
    34. if(a!=b) p[a]=b;//假如不在一个集合,则加上该条边
    35. else ans+=w;//反之该条边就是多余不要的加上答案里
    36. }
    37. cout<//输出总的减最小生成数的
    38. return 0;
    39. }

    3.繁忙的都市

    信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    1. #include
    2. using namespace std;
    3. const int N=310,M=N*N;
    4. struct Edge
    5. {
    6. int a,b,w;
    7. bool operator < (const Edge&t) const//重载小于号,使排序按照w排
    8. {
    9. return w
    10. }
    11. }e[M];
    12. int p[N];
    13. int find(int x)//并查集
    14. {
    15. if(p[x]!=x) p[x]=find(p[x]);
    16. return p[x];
    17. }
    18. int main()
    19. {
    20. int n,m,ans;
    21. cin>>n>>m;
    22. for(int i=0;i
    23. {
    24. int a,b,w;
    25. cin>>a>>b>>w;
    26. e[i]={a,b,w};
    27. }
    28. for(int i=1;i<=n;i++) p[i]=i;//并查集初始化操作
    29. sort(e,e+m);//排序
    30. for(int i=0;i
    31. {
    32. int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
    33. if(a!=b)//假如不在一个连通块中,则加上他
    34. {
    35. p[a]=b;
    36. ans=w;//更新最大值
    37. }
    38. }
    39. cout<-1<<' '<
    40. return 0;
    41. }

    4.联络员

    信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    这题只能用kruskal,因为有多个连通块,而prim只能处理一个连通块

    1. #include
    2. using namespace std;
    3. const int N=2010,M=1e4+10;
    4. int res=0;
    5. struct Edge
    6. {
    7. int a,b,w;
    8. bool operator <(const Edge&t)const//重载小于号
    9. {
    10. return w
    11. }
    12. }e[M];
    13. int p[N];
    14. int find(int x)//并查集
    15. {
    16. if(p[x]!=x) p[x]=find(p[x]);
    17. return p[x];
    18. }
    19. int main()
    20. {
    21. int n,m,cnt=0;
    22. cin>>n>>m;
    23. for(int i=1;i<=n;i++) p[i]=i;//初始化
    24. for(int i=0;i
    25. {
    26. int t,a,b,w;
    27. cin>>t>>a>>b>>w;
    28. if(t&1)//假如是必选
    29. {
    30. res+=w;//则加上边权
    31. a=find(a),b=find(b);
    32. p[a]=b;//加到同一个连通块中
    33. }
    34. else e[cnt++]={a,b,w};//否则非必选
    35. }
    36. sort(e,e+cnt);//排序
    37. for(int i=0;i
    38. {
    39. int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
    40. if(a!=b)//假如不在一个连通块
    41. {
    42. res+=w;//则加上边权
    43. p[a]=b;//加到同一个连通块中
    44. }
    45. }
    46. cout<
    47. return 0;
    48. }

    5.连接格点

    信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    就是给你已经连接了的点,让你加上某些边使他连通,也就是最小生成树,但是不能用prim,可能给出的边有环,只能用kruskal

    1. #include
    2. using namespace std;
    3. const int N=1010,M=N*N,K=2*M;
    4. int ids[N][N];//用来将坐标映射到点
    5. int n,m,k;
    6. struct Edge
    7. {
    8. int a,b,w;
    9. }e[K];
    10. int p[M];
    11. int find(int x)//并查集
    12. {
    13. if(p[x]!=x) p[x]=find(p[x]);
    14. return p[x];
    15. }
    16. void edge()
    17. {
    18. int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1},dw[4]={1,2,1,2};//四个方向
    19. for(int s=0;s<2;s++)//s表示余数,0表示打横走,1表示纵着走
    20. for(int i=1;i<=n;i++)
    21. for(int j=1;j<=m;j++)
    22. for(int u=0;u<4;u++)
    23. if(u%2==s)//走的途径
    24. {
    25. int x=i+dx[u],y=j+dy[u],w=dw[u];
    26. if(x<=0||x>n||y<=0||y>m) continue;//假如越界
    27. int a=ids[i][j],b=ids[x][y];//获取当前位置
    28. if(a//为了避免重复假如
    29. }
    30. }
    31. int main()
    32. {
    33. cin>>n>>m;
    34. for(int i=1;i<=n*m;i++) p[i]=i;//初始化
    35. for(int i=1,t=1;i<=n;i++)//映射坐标为点
    36. for(int j=1;j<=m;j++,t++)
    37. ids[i][j]=t;
    38. int x1,x2,y1,y2;
    39. while(cin>>x1>>y1>>x2>>y2)
    40. {
    41. int a=ids[x1][y1],b=ids[x2][y2];
    42. p[find(a)]=find(b);//假如是连通块了,则加到同个连通块中
    43. }
    44. edge();//处理每个走的方式
    45. int res=0;
    46. for(int i=0;i
    47. {
    48. int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
    49. if(a!=b)//假如不在一个连通块
    50. {
    51. res+=w;//则加上边权
    52. p[a]=b;//加到同一个连通块中
    53. }
    54. }
    55. cout<
    56. return 0;
    57. }

  • 相关阅读:
    出海必读,汇量科技联合SensorTower发布《2022国内手游出海白皮书》
    面向碳中和的公共建筑室内环境营造再认识
    Vue3+Vite+ElementPlus管理系统常见问题
    【图像分割】图像检测(分割、特征提取)、各种特征(面积等)的测量和过滤(Matlab代码实现)
    【C++】可变参数模板
    做了8年前端,细说那些曾经让你浴霸不能的后端
    线性代数基础-行列式
    ElasticSearch
    Hbuilder本地调试微信H5项目(三)--调用微信接口获取用户信息
    spring-boot-maven-plugin插件 —— 重新打包分类
  • 原文地址:https://blog.csdn.net/m0_63729880/article/details/126094791