zoukankan      html  css  js  c++  java
  • 最小生成树实验

    一、实验目的

    1.进一步掌握图的结构及非线性特点,递归特点和动态性。

    2.进一步巩固最小生成树的两种求解算法。

    二、实验原理

    从任意一顶点 v0 开始选择其最近顶点 v1 构成树 T1,再连接与 T1 最近顶点 v2 构成树 T2, 如此重复直到所有顶点均在所构成树中为止。

    最小生成树(MST):权值最小的生成树。

    生成树和最小生成树的应用:要连通n个城市需要n-1条边线路。可以把边上的权值解释为线路的造价。则最小生成树表示使其造价最小的生成树。

    构造网的最小生成树必须解决下面两个问题:

    1、尽可能选取权值小的边,但不能构成回路;

    2、选取n-1条恰当的边以连通n个顶点;

    MST性质:假设G=(V,E)是一个连通网,U是顶点V的一个非空子集。若(u,v)是一条具有最小权值的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树。

    prim算法假设G=(V,E)是连通的,TE是G上最小生成树中边的集合。算法从U={u0}(u0∈V)、TE={}开始。重复执行下列操作:

    在所有u∈U,v∈V-U的边(u,v)∈E中找一条权值最小的边(u0,v0)并入集合TE中,同时v0并入U,直到V=U为止。

    此时,TE中必有n-1条边,T=(V,TE)为G的最小生成树。

     Prim算法的核心:始终保持TE中的边集构成一棵生成树。

    注意:prim算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图

    三、参考程序

    #include<stdio.h>
    #define max 7
    int quan[max][max];//放权值
    int useing[max],used[max];//useing表示已经被选中的节点,used表示未被选中的节点
    struct biao{
    int index;
    int quanzhi;
    }b[max-1];//用来存放quanzhi数组中某一行的数据,
    void tree(){
    int min=1000,j,miny,minx=1,i=0,k,uing=1,ud=1,count=0,z,t=0,w=0;
    //min=1000表示路不通。 minx表示第几行,miny 表示第几列,count用来计算总的最小权值
    while(true){
    i=minx;
    useing[uing]=i;//把被选中的节点给useing我们从1节点开始
    uing++;
    for(k=1;k<max;k++){
    if(minx==used[k]){
    used[k]=1000;//如果节点亦被选中把该位置=1000

    }
    }


    printf(" i--%d ",i);
    for(k=1, j=1;j<max;j++,k++){//给b数组初始化
    b[k].index=j;//下表给它
    b[k].quanzhi=quan[i][j];//权值给他

    }//for
    min=1000;
    for(k=1;k<max;k++){//寻找与该节点相连的权值最小的那个节点
    if(min>b[k].quanzhi){
    min=b[k].quanzhi;
    miny=k;//记录下该节点的下表
    }
    }

    quan[i][miny]=1000;
    quan[miny][i]=1000; //把找到的节点的数=1000;
    printf(" ---1--- ");

    /*

    printf(" min--%d ",min);
    printf(" minx--%d ",minx);
    for(i=1;i<max;i++){
    printf("%d ",b[i].quanzhi);
    }
    printf(" ");
    for(i=1;i<max;i++){
    for(j=1;j<max;j++)
    printf("%d ",quan[i][j]);
    printf(" ");
    }
    */

    minx=miny;//把找到的节点的下表给minx,为了便利找到该节点的最小权值
    z=0;
    for(i=1;i<max;i++){
    if(miny==useing[i]){//形成环路了
    z=1;
    w=1;

    }

    }
    if(z==1){
    for(i=1;i<max;i++){//从还未 被赵国的节点再次开始开始
    if(used[i]!=1000){
    minx=used[i];//把未被选中过的下标给minx

    used[i]=1000;//并把used该位置=1000
    break;
    }
    }
    }

    // useing[uing]=minx;
    // printf(" using--%d ",uing);
    // uing++;




    count=count+min;//求最小权值总和
    // printf(" --count-%d--- ",count);
    if(t==6)//结束循环,
    break;
    t=0;
    for(i=1;i<max;i++){//判断所有顶点是否全被便利过
    if(used[i]==1000){
    t++;
    }

    }
    if(w==1){//减去那个形成环路时多加的权值
    count=count-min;

    }
    w=0;

    }
    for(i=1;i<max;i++){
    printf("%d ",useing[i]);
    }
    printf(" ");
    for(i=1;i<max;i++){
    printf("%d ",used[i]);
    }
    printf(" ");

    printf(" --count1-%d--- ",count);
    }


    int main(){
    int i,j,t=0,number,weight;;
    for(i=0;i<max;i++){
    for(j=0;j<max;j++)
    quan[i][j]=1000;
    }
    for(i=0;i<max;i++){
    used[i]=i;
    useing[i]=0;
    }

    FILE *fr;

    fr = fopen("D:\123.txt","r");
    if(!fr)
    {
    printf("fopen failed ");
    }
    while(fscanf(fr,"%d%d%d", &i, &j, &weight) != EOF)
    {
    quan[i][j] = weight;
    quan[j][i] = weight;
    }

    for(i=1;i<max;i++){
    for(j=1;j<max;j++)
    printf("%d ",quan[i][j]);
    printf(" ");
    }
    for(i=1;i<max;i++){
    printf("%d ",useing[i]);
    }

    for(i=1;i<max;i++){
    printf("%d ",used[i]);
    }
    tree();
    return 0;

    }

  • 相关阅读:
    ES6 promise 常用方法介绍
    js判断元素是否在可视区域里
    alert之后才执行
    jquery总结和注意事项
    java中unicode和中文相互转换
    html href页面跳转获取参数
    myBatis批量添加实例
    mybatis中返回自动生成的id
    遍历map的四种方法
    MyBatis魔法堂:Insert操作详解(返回主键、批量插入)
  • 原文地址:https://www.cnblogs.com/huifeidezhuzai/p/9278962.html
Copyright © 2011-2022 走看看