破圈法求解最小生成树c语言实现(已验证)

破圈法求解最小生成树c语言实现(已验证)

破圈法求解最小生成树c语言实现(已验证)

下面是算法伪代码,每一个算法都取一个图作为输入,并返回一个边集T。

对该算法,证明T是一棵最小生成树,或者证明T不是一棵最小生成树。此外,对于每个算法,无论它是否能计算出一棵最小生成树,都要给出其最有效的实现。

MAYBE-MST-A(G,w)

Sort the edges into nonincreasing order of edge weights w

T<-E

For each edge e, taken in nonincreasing order by weight

Do if T-{e} is a connected graph

    Then T<-T-e

Return T

 

 

算法基本思想:

先将图G的边按照权的递减顺序排列后,依次检验每条边,在保持连通的情况下,每次删除最大权边,直到所有边都被遍历到无法删除任何一边(或余下n-1条边为止)。

证明:

生成树证明:

1、     如果给定连通图G没有回路,那么G本身就是一棵生成树

2、     如果G中只有一个回路,则删去G的回路上的一条边(不删除节点),则产生的图仍是连通的且没有回路,则得到的子图就是G的一棵生成树;

3、     如果G的回路不止一个,只要删去每一个回路上的一条边,知道G的子图是连通且没有回路且与图G有一样的结点集,那么这个子图就是一棵生成树。

4、     重复步骤3,则直到所有边都不能删除,由于删除判断条件,得到的子图就是一棵生成树。

MST证明:

若在某个回路C中有一条唯一的最长边,则T­­­*中一定不含这条边,因为优先删除回路中最长的边。

若在某个边e的割集中有一条唯一一条最短边,则T*中一定含有这条边(The Cut Property:考虑图G中的一条边e。如果存在一个cut(A,B),使得e是所有跨越该割的所有边中权重最小者,则e一定在G的MST中。

),且不含有其他边,因为一旦含有其他边就构成了回路(Lonely-Cut Corollary如果边e是跨越了cut(A, B)的唯一一条边,则e不可能在任一圈中。)。

反向证明:假设T*中跨越cut(A,B)的边不只一条,则在算法结束之前一定会遍历到其中的成圈的边(Double-Crossing),根据权值选取方法和删除圈的一边仍为连通图的条件,一定会将权值较大的边删除,直到无环且剩下的唯一一条边是最短边。

算法变量:

a[n][n]:带权图的邻接矩阵,a[i][j]=w或a[i][j]=0;

max:标记当前找到的准备删去的边的权值;

p:标记找到的要删去的权值所在的行号;

q:标记找到的要删去的权值所在的列好;

am:标记找到的最大元素(am是为了保护权值大但不能删的边),如果a[i][j]不能删除,则可以让a[p][q]=am,a[q][p]=am来还原刚才删去的边;

I,j:二维数组的行号和列号

sm:图的边数,每删除一个边,sm就减1,当sm=n-1时,结束

wt:最小生成树的权值和

算法实现(c语言)

  1 #include<stdio.h>
    BY Yuanshuai Zheng,UESTC
  2 #define n 5
  3 int a[n][n];
  4 int flag,am,p,q;
  5 INPUT()
  6 {
  7     int i,j;
  8     printf("输入图的带权邻接矩阵:\n");
  9     for(i = 0;i<n;i++)
 10     {
 11         for(j=0;j<n;j++)
 12         scanf("%d",&a[i][j]);
 13     }
 14  } 
 15  OUTPUT(int a[n][n])
 16  {
 17      int i,j;
 18      for(i=0;i<n;i++)
 19      {
 20          for(j=0;j<n;j++)
 21          printf("%5d",a[i][j]);
 22          printf("\n");
 23      }
 24  }
 25  MAX(int a1[n][n],int am1,int p1,int q1)
 26  {
 27      int i,j,ptm,qtm;
 28      int max;
 29      max = 0;
 30      for(i=0;i<n;i++)
 31      {
 32          for(j=i;j<n;j++)
 33          if((a1[i][j]>max)&&(a1[i][j]<=am1)&&((i!=p1)||(j!=q1)))
 34          {
 35              max = a1[i][j];
 36              ptm = i;
 37              qtm = j;
 38 
 39         }
 40      }
 41     am = max;
 42     printf("max=%5d\t",am);
 43      p = ptm;
 44      q = qtm;
 45      a[p][q]=0;
 46      a[q][p]=0;
 47  }
 48  WSHALL(int array[n][n])
 49  {
 50      int i,j,k,m=0;
 51      int r[n][n],B[n][n];
 52      for(i=0;i<n;i++)
 53      {
 54          for(j=0;j<n;j++)
 55          {
 56              r[i][j]=0;
 57              B[i][j]=array[i][j];
 58              //分界线
 59              if(array[i][j]>=1)
 60                 B[i][j]=1;
 61             else 
 62                 B[i][j]=0; 
 63             //分界线 
 64          }
 65      }
 66     for(j=0;j<n;j++)
 67     {
 68         for(i=0;i<n;i++)
 69             if(B[i][j]>=1)
 70                 {
 71                     for(k=0;k<n;k++)
 72                         {
 73                             if(B[k][i]>=1)
 74                             {
 75                                 B[k][j]=B[j][k]=1;
 76                             }
 77                         }
 78                 }
 79     }
 80     for(i=0;i<n;i++)
 81     {
 82         for(j=0;j<n;j++)
 83             if(!B[i][j])
 84             {
 85                 return 0;    
 86             }
 87     }
 88     return 1;
 89 }
 90     
 91 //方法1 
 92 //        for(k=0;k<n;k++)
 93 //        B[i][j]=B[i][k]+B[j][k];                    
 94 //        }
 95 //    }
 96 //    for(i=0;i<n;i++)
 97 //    {
 98 //        for(j=0;j<n;j++)
 99 //        {
100 //            r[i][j]=B[i][j];
101 //            {
102 //                if((r[i][j]>=1)||(i==j))
103 //                    m=m+1;
104 //            }
105 //        }
106 //    }
107 //    printf("m=%d\t",m);
108 //    if(m==n*n)
109 //        flag = 1;
110 //    else
111 //        flag=0;
112 //    return(flag);
113 
114 int main()
115 {
116     int i,j,sm,wt=0;
117     am = 10000,p=-1,q=-1,sm=0;
118     INPUT();
119     for(i=0;i<n;i++)
120     {
121         for(j=i;j<n;j++)
122         {
123             if(a[i][j]>0)
124                 sm = sm+1;
125         }
126     }
127     printf("\nsm=%d\n",sm);
128     printf("输出图的带权邻接矩阵:\n");
129     OUTPUT(a);
130     printf("\n");
131     while(sm>n-1)
132     {
133         MAX(a,am,p,q);
134         flag=WSHALL(a);//华沙尔算法判断是否连通 
135         //printf("flag= %d",flag);
136         {
137             if(flag==1)
138             {
139                 sm=sm-1;
140                 //printf("flag= %d",flag);
141             }            
142             else
143             {
144                 a[p][q]=am;
145                 a[q][p]=am;
146             }
147         }
148     }
149     for(i=0;i<n;i++)
150     for(j=i;j<n;j++)
151     {
152         wt=wt+a[i][j];
153     }
154     printf("\n\n输出最小生成树的带权邻接矩阵:\n");
155     OUTPUT(a);
156     printf("最小生成树的树权是: %d\n",wt);
157 }
158      

代码验证:

例子:

0

6

10

0

0

6

0

3

8

5

10

3

0

6

7

0

8

6

0

0

0

5

7

0

0

posted @ 2018-04-18 02:15 Edge_of_Eternity 阅读(...) 评论(...) 编辑 收藏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值