zoukankan      html  css  js  c++  java
  • 次小生成树

    别人都写最小生成树,我来个次小的,您可别看是小,可是比最小生成树难了不少。(虽然可能对于某个强的了不得的大佬(点击进入翻译)来说,他应该会很“傲慢”的说:“这不很简单吗”)     当时五一我在QBXT上课的时候这个题我想了几想我才想出来的。

    下面我给出代码(不会前向星和并查集的去看我的其他博客)

    以下代码是在Kruskal算法的基础上进行修改,加入对x,y两点在最小生成树上路径中最长边的计算,存入length[ ][ ]数组。使用链式前向星记录每个集合都有哪些点。为了合并方便,除了head[ ]记录每条邻接表的头节点的位置外,end[ ]记录每条邻接表尾节点的位置便于两条邻接表合并。mst为最小生成树的大小,seemst为次小生成树的大小。在存在权值相同的边的情况下,seemst有可能等于mst。

    并查集部分代码略详见我的另一篇博客(在此只给出声明)

    1 //并查集部分 
    2 const int maxn = 1010;
    3 int UFSTree[maxn];
    4 int find(int x);
    5 void merge(int x , int y);
    并查集

    下面是Kruskal部分

     1 //kruskal
     2 const int maxe = 100010;
     3 struct node{
     4     int a , b;
     5     int w;
     6     bool select;
     7 }edge[maxe];
     8 
     9 bool cmp(node a , node b){
    10     if(a.w != b.w) return a.w < b.w;
    11     if(a.a != b.a) return a.a < b.a;
    12     return a.b < b.b;
    13 } 
    14 
    15 //链式前向星的数据结构
    16 struct node1{
    17     int to;
    18     int next;
    19 }; 
    20 
    21 node1 link[maxn];        //边数组 
    22 int il;                    //边数组中数据的个数 
    23 int head[maxn];            //邻接表的头节点位置 
    24 int end[maxn];            //邻接表的尾节点位置 
    25 int length[maxn][maxn];    //每两点在最小生成树上路径中最长的边
    26 void kruskal(node * edge , int  n , int m){
    27     int k = 0;
    28     int  i , x , y;
    29     int w , v;
    30     /* 初始化邻接表,对于每个节点添加一条指向其自身的边,
    31     表示以i为代表元的集合只有点i */
    32     for(il = 0 ; il < n ; il ++){
    33         link[il].to = il + 1;
    34         link[il].next = head[il + 1];
    35         end[il + 1] = il;
    36         head[il + 1] = il;
    37     } 
    38     sort(edge + 1 , edge + 1 + m , cmp);
    39     for(i = 1 ; i <= m ; i ++){
    40         if(k == n - 1)break;
    41         if(edge[i].w < 0)continue;
    42         x = find(edge[i].a);
    43         y = find(edge[i].b);
    44         if(x != y){
    45             //修改部分,遍历两个节点所有的集合
    46             for(w = head[x] ; w != -1 ; w = link[w].next){
    47                 for(v = head[y] ; v != -1 ; ){
    48                     /*每次合并两个等价类的时候,分别属于两个等价类的两个
    49                     点间的最长边一定是当前加入的边*/
    50                     length[link[w].to][link[v].to] = length[link[v].to][link[w].to] = edge[i].w;
    51                 }
    52             } 
    53             //合并两个邻接表
    54             link[end[y]].next = head[x];
    55             end[y] = end[x];
    56             merge(x , y);
    57             k ++;
    58             edge[i].select = 1;
    59         }
    60     }
    61 } 
    62 int main(){
    63     //先初始化和建图,然后进行下面的操作
    64     int mst , secmst;
    65     kruskal(edge , n , m );
    66     mst = 0;
    67     for(i = 1 ; i  <= m ; i ++){
    68         if(edge[i].select)mst += edge[i].w;
    69     }
    70     secmst = INF;
    71     for(i = 1 ; i <= m ; i ++){
    72         if(! edge[i].select)secmst = min (secmst , mst + edge[i].w - length[edge[i].a][edge[i].b]);
    73     }
    74 }
    Kruskal

    整个算法运行了一次Kruskal 算法,时间复杂是O(m log m),同时又对整个length[ ][ ] 进行赋值, 时间复杂度为O(n²),最终又进行了时间复杂度为O(m)的遍历,总的时间复杂度为O(m log m + n²)。

    大佬推荐ZHT大佬

  • 相关阅读:
    Java实现 LeetCode 799 香槟塔 (暴力模拟)
    Java实现 LeetCode 799 香槟塔 (暴力模拟)
    ASP.NET中使用Entity Framework开发登陆注册Demo
    ASP.NET中使用Entity Framework开发登陆注册Demo
    ASP.NET中使用Entity Framework开发登陆注册Demo

    requirejs
    转一个网址,canvas用法
    这是个排序,摘的,记一下
    今天面前端哦 2015 08 27
  • 原文地址:https://www.cnblogs.com/2464638814-xch/p/6821785.html
Copyright © 2011-2022 走看看