数据结构11.24

 问题 A: 图的最小生成树-Prim算法

题目描述

Prim算法是求解带权图的最小生成树的经典算法。其步骤如下:
E1:任取一个顶点构成U={v0};构造向量cost[0…n-1]和adj[0…n-1],cost[i]表示顶点vi到U的最短边的长度,adj[i]表示顶点vi到U的最短边在U中的邻接点的下标;其中,vi∈V-U。初始时,生成树T为空集。
E2:重复n-1次
E21:从V-U中选出cost值最小的顶点vk,将边<vk, vadj[k]>加入到生成树T中,然后将vk并入U中;
E22:修正V-U中各顶点的cost值和adj值;

本题要求根据Prim算法,求解第一步状态下的cost和adj两个向量。

输入格式

输入为邻接矩阵存储的图,第一行为正整数n(小于100),表示图中顶点个数
接下来是n行,每行为n个空格隔开的非负整数。0表示两个顶点之间没有直达边,非0表示有直达边。且该数字为对应直达边的权重。

输出格式

假设第一步选择将序号最小的0号节点并入集合U。按照样例格式输出cost和adj两个向量

输入样例 复制

7
0 10 9 13 0 0 0
10 0 0 15 7 0 12
9 0 0 4 0 3 0
13 15 4 0 0 22 23
0 7 0 0 0 0 20
0 0 3 22 0 0 32
0 12 0 23 20 32 0

输出样例 复制

0 - -
1 10 0
2 9 0
3 13 0
4 - -
5 - -
6 - -

 原码

#include<bits/stdc++.h>
using namespace std;

int main(){
   int a;cin>>a;
   int mat[a+5];
   for(int i=0;i<a;i++){
       cin>>mat[i];
       if(mat[i])
       cout<<i<<" "<<mat[i]<<" 0"<<endl;
       else
           cout<<i<<" - -"<<endl;
       
   }
}

问题 B: 图的最小生成树-Kruskal算法

题目描述

Kruskal算法是最小生成树的经典算法,其步骤为:
E1:将所有的边按权值排序;
E2:设每个顶点为一个独立的点集,生成树T为空集;
E3:依序扫描每一条边<vi,vj>,直到已输出n-1条边:
E31:若vi、vj不在同一点集中,则将该边加入生成树T中,并合并这两个点集;否则舍弃该边;
本题要求读入带权图,对其所有边按权值排序后输出。

输入格式 

输入为邻接矩阵存储的图,第一行为正整数n(小于100),表示图中顶点个数
接下来是n行,每行为n个空格隔开的非负整数。0表示两个顶点之间没有直达边,非0表示有直达边。且该数字为对应直达边的权重。

输出格式

对所有边按权重排序后输出。如果图只有1个点(即没有边),则直接输出空行。

输入样例 

7
0 10 9 13 0 0 0
10 0 0 15 7 0 12
9 0 0 4 0 3 0
13 15 4 0 0 22 23
0 7 0 0 0 0 20
0 0 3 22 0 0 32
0 12 0 23 20 32 0

输出样例 

<2,5>:3
<5,2>:3
<3,2>:4
<2,3>:4
<4,1>:7
<1,4>:7
<2,0>:9
<0,2>:9
<1,0>:10
<0,1>:10
<1,6>:12
<6,1>:12
<0,3>:13
<3,0>:13
<1,3>:15
<3,1>:15
<4,6>:20
<6,4>:20
<3,5>:22
<5,3>:22
<6,3>:23
<3,6>:23
<5,6>:32
<6,5>:32

数据范围与提示

注意题目的测试数据构造时用的排序算法如下:
for(int i=0;i<n;i++)
   for(int j=i+1;j<n;j++)
        if(a[j]<a[i]) swap(i,j);  // 交换

#include<bits/stdc++.h>
using namespace std;

struct faze{
    int row,col;
    int info;
};

faze mat[123456];
void swap(int i,int j){
   faze T;
   T=mat[i];
   mat[i]=mat[j];
   mat[j]=T;
}
int main(){
    int a;cin>>a;
    if(a==1){
        cout<<endl;return 0;
    }
    int cnt=0;
    for(int i=0;i<a*a;i++){//临接矩阵转化为一维数组
        cin>>mat[cnt].info;
        if(!mat[cnt].info)continue;//剔除零元
        mat[cnt].row=i/a;//记录行列
        mat[cnt++].col=i%a;
    }
    for(int i=0;i<cnt;i++){//从小到大排序
        for(int j=i+1;j<cnt;j++)
        if(mat[j].info<mat[i].info)swap(i,j);
    }
    for(int i=0;i<cnt;i++){//输出
        if(mat[i].info!=0){
            printf("<%d,%d>:%d\n",mat[i].row,mat[i].col,mat[i].info);
        }
    }
    return 0;
}

 问题 C: 算法7-9:最小生成树

题目描述

最小生成树问题是实际生产生活中十分重要的一类问题。假设需要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条线路。这时,自然需要考虑这样一个问题,即如何在最节省经费的前提下建立这个通信网。

可以用连通网来表示n个城市以及n个城市之间可能设置的通信线路,其中网的顶点表示城市,边表示两个城市之间的线路,赋于边的权值表示相应的代价。对于n个顶点的连通网可以建立许多不同的生成树,每一棵生成树都可以是一个通信网。现在,需要选择一棵生成树,使总的耗费最小。这个问题就是构造连通网的最小代价生成树,简称最小生成树。一棵生成树的代价就是树上各边的代价之和。

而在常用的最小生成树构造算法中,普里姆(Prim)算法是一种非常常用的算法。以下是其算法的大致结构:

在本题中,读入一个无向图的邻接矩阵(即数组表示),建立无向图并按照以上描述中的算法建立最小生成树,并输出最小生成树的代价。

输入格式

输入的第一行包含一个正整数n,表示图中共有n个顶点。其中n不超过50。 以后的n行中每行有n个用空格隔开的整数,对于第i行的第j个整数,如果不为0,则表示第i个顶点和第j个顶点有直接连接且代价为相应的值,0表示没有直接连接。当i和j相等的时候,保证对应的整数为0。 输入保证邻接矩阵为对称矩阵,即输入的图一定是无向图,且保证图中只有一个连通分量。

输出格式

只有一个整数,即最小生成树的总代价。请注意行尾输出换行。

输入样例

4
0 2 4 0
2 0 3 5
4 3 0 1
0 5 1 0
输出样例  

6
数据范围与提示

在本题中,需要掌握图的深度优先遍历的方法,并需要掌握无向图的连通性问题的本质。通过求出无向图的连通分量和对应的生成树,应该能够对图的连通性建立更加直观和清晰的概念。
 

#include<bits/stdc++.h>
using namespace std;
#define ff 0x3f
#define maxs 100
struct Gragh{
   int vexnumber;
   string vexinfo[maxs];
   int matrix[maxs][maxs];
};

int prim(Gragh g){
   int visit[maxs];int dis[maxs];//存放某点与其他点距离
   int n=g.vexnumber;int res=0;
   memset(visit,0,sizeof(visit));//开始全未访问
   memset(dis,0x3f,sizeof(dis));//开始定为极大值
   for(int i=0;i<n;i++){
      int f=-1;
      for(int j=0;j<n;j++){
         if(!visit[j]&&(f==-1||dis[j]<dis[f])){
      //开始f点选为0,后面选为dis数组为最小值且未访问的点
            f=j;
         }
      }
      if(i&&dis[f]==ff)return 0;
      if(i)res+=dis[f];
      for(int k=0;k<n;k++){//若各顶点与f点的距离小于dis,更新dis数组
         dis[k]=min(dis[k],g.matrix[k][f]);
      }
      visit[f]=1;
   }
   return res;
}
int main(){
   int a;cin>>a;
   Gragh g;g.vexnumber=a;
   for(int i=0;i<a;i++){
      for(int j=0;j<a;j++){
      cin>>g.matrix[i][j];
      if(!g.matrix[i][j])
      g.matrix[i][j]=ff;//不为0数调整为最大值
      }
   }
   cout<<prim(g)<<endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值