• 次小生成树


    思想还是很重要的....

    首先,次小生成树就是用一条边替换最小生成树中的另一条边. 代价就是两条边的权值差.

    证明:

    我们把"在树上连一条新的边形成一个环,再删掉那个环上一条不是新边的边"的操作叫做边的替换.

    替换的代价就是新边权减掉删掉的那条边的边权.

    首先,最小生成树通过若干次替换总能够变成次小生成树,这是显然的.

    我们把第一次替换的代价记为v1.剩下的所有替换的代价和记为v2.

    首先v1和v2均不小于0.否则,对当前的最小生成树应用这些替换,会使总的权值和减小,当前树就不是最小生成树了.

    那么如果v2等于0,相当于我们只进行第一次替换,然后什么都不干,于是我们仅通过一次替换得到次小生成树.

    如果v2大于0,那么它的权值一定大于只进行第一次替换的权值,此时新树的权值比原树大v1+v2.

    而我们肯定有一颗树的权值比原树大v1.因此,我们得到:新树的权值比原树大,还比进行了一次替换的树大.

    所以这棵树肯定不是次小生成树.

    于是次小生成树一定是仅通过一次在最小生成树上的边替换得到的.

    假设我们用边(i,j) 替换边 (a,b) ,边权函数为 e ,可知 e(i,j)-e(a,b) 应当最小.

    我们枚举非树边 (i,j) ,然后计算树上i到j路径上的最长边.

    对于常规生成树,显然可以倍增求 LCA(i,j) 以及求路径上的最值.

    Kruskal的次小生成树不会TAT

    对于Prim,需要开一个数组 f(i,j) 表示最小生成树上i到j的路径中的最长边长度.

    维护的时候,如果我们新连了边 (i,j) ,其中 i 不在当前树中, j 在当前树中,那么有递推式

    对于每一个当前树上的点k, f(i,k) = f(k,i) = max( f(k,j) , e(i,j) );

    然后把 (i,j) 从边表中剔除(或者标记一下),之后我们枚举非树边的时候就方便一些......

    为了取得j,还要记录每个节点连到当前树的最短边是哪一个节点的. 维护距离数组的时候顺带更新.

     

    AC VIJOS 1070 最小生成树+次小生成树

    ExPrim

    #include <cstdio>
    #include <fstream>
    #include <iostream>
     
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
     
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <stack>
    #include <list>
     
    typedef unsigned int uint;
    typedef long long int ll;
    typedef unsigned long long int ull;
    typedef double db;
     
    using namespace std;
     
    inline int getint()
    {
        int res=0;
        char c=getchar();
        bool mi=false;
        while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
        while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
        return mi ? -res : res;
    }
    inline ll getll()
    {
        ll res=0;
        char c=getchar();
        bool mi=false;
        while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
        while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
        return mi ? -res : res;
    }
    
    //==============================================================================
    //==============================================================================
    //==============================================================================
    //==============================================================================
    
    const ll INF=((ll)1<<56)-1;
    
    int n,m;
    ll M[505][505];
    ll S[505][505];
    ll D[505];
    int E[505];
    ll F[505][505];
    bool used[505];
    
    
    void putres(ll x)
    { printf("Cost: %I64d
    ",x); }
    
    int main()
    {
        n=getll();
        m=getll();
        
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        M[i][j]=S[i][j]=INF;
        
        for(int i=0;i<m;i++)
        {
            int a=getint()-1;
            int b=getint()-1;
            ll v=getint();
            if(v<M[a][b])
            {
                S[a][b]=S[b][a]=M[a][b];
                M[a][b]=M[b][a]=v;
            }
            else if(v<S[a][b])
                S[a][b]=S[b][a]=v;
        }
        
        //Prim
        for(int i=1;i<n;i++) D[i]=INF;
        ll res=0;
        int d;
        for(d=0;d<n;d++)
        {
            int x=-1;
            ll mi=INF;
            for(int i=0;i<n;i++)
            if(!used[i] && mi>D[i])
            { mi=D[i]; x=i; }
            
            if(mi==INF) break; //unable to find any edge.
            used[x]=true;
            res+=mi;
            
            F[E[x]][x]=F[x][E[x]]=mi;
            for(int i=0;i<n;i++)
            if(used[i] && i!=x && i!=E[x])
            F[i][x]=F[x][i]=max(F[i][E[x]],mi);
            
            M[E[x]][x]=M[x][E[x]]=S[x][E[x]];
            
            for(int i=0;i<n;i++)
            if(!used[i] && D[i]>M[i][x])
            { D[i]=M[i][x]; E[i]=x; }
        }
        
        if(d!=n) { putres(-1),putres(-1); return 0; }
        
        bool tag=true;
        for(int i=0;i<n && tag;i++)
        for(int j=0;j<n && tag;j++)
        if(M[i][j]!=INF) tag=false;
        
        if(tag) { putres(res),putres(-1); return 0; }
        
        ll delta=INF;
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        if(M[i][j]!=INF)
        delta=min(delta,M[i][j]-F[i][j]);
        
        putres(res),putres(delta+res);
        
        return 0;
    }
    View Code

    ExKruskal

      1 #include <cstdio>
      2 #include <fstream>
      3 #include <iostream>
      4  
      5 #include <cstdlib>
      6 #include <cstring>
      7 #include <algorithm>
      8 #include <cmath>
      9  
     10 #include <queue>
     11 #include <vector>
     12 #include <map>
     13 #include <set>
     14 #include <stack>
     15 #include <list>
     16  
     17 typedef unsigned int uint;
     18 typedef long long int ll;
     19 typedef unsigned long long int ull;
     20 typedef double db;
     21  
     22 using namespace std;
     23  
     24 inline int getint()
     25 {
     26     int res=0;
     27     char c=getchar();
     28     bool mi=false;
     29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     31     return mi ? -res : res;
     32 }
     33 inline ll getll()
     34 {
     35     ll res=0;
     36     char c=getchar();
     37     bool mi=false;
     38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
     39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
     40     return mi ? -res : res;
     41 }
     42 
     43 //==============================================================================
     44 //==============================================================================
     45 //==============================================================================
     46 //==============================================================================
     47 
     48 const ll INF=(ll(1)<<56)-1;
     49 
     50 int n,m;
     51 
     52 struct vedge
     53 {
     54     int a,b;
     55     ll v;
     56     bool used;
     57 }E[200000];
     58 int p[200000];
     59 bool cmp(int x,int y)
     60 { return E[x].v<E[y].v; }
     61 
     62 //union find
     63 int ft[1000];
     64 void INIT(int size)
     65 { for(int i=0;i<=size;i++) ft[i]=i; }
     66 int findf(int x)
     67 { return ft[x]==x ? x : ft[x]=findf(ft[x]); }
     68 void con(int a,int b)
     69 { ft[findf(a)]=findf(b); }
     70 
     71 struct edge
     72 {
     73     int in;
     74     ll v;
     75     edge*nxt;
     76 }pool[10000];
     77 edge*et=pool;
     78 edge*eds[1000];
     79 void addedge(int i,int j,ll v)
     80 {
     81     et->in=j; et->v=v; et->nxt=eds[i]; eds[i]=et++;
     82     et->in=i; et->v=v; et->nxt=eds[j]; eds[j]=et++;
     83 }
     84 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
     85 
     86 //DFS
     87 int f[11][1050];
     88 ll mx[11][1050];
     89 int dep[1050];
     90 ll v[1050];
     91 int curd;
     92 void DFS(int x,ll k)
     93 {
     94     dep[x]=curd;
     95     v[x]=k;
     96     mx[0][x]=max(v[x],v[f[0][x]]);
     97     
     98     curd++;
     99     FOREACH_EDGE(i,x)
    100     if(i->in!=f[0][x])
    101     {
    102         f[0][i->in]=x;
    103         DFS(i->in,i->v);
    104     }
    105     curd--;
    106 }
    107 
    108 void gen()
    109 {
    110     for(int d=1;d<11;d++)
    111     {
    112         for(int i=0;i<n;i++)
    113         {
    114             f[d][i]=f[d-1][f[d-1][i]];
    115             mx[d][i]=max(mx[d-1][i],mx[d-1][f[d-1][i]]);
    116         }
    117     }
    118 }
    119 
    120 int getLCA(int a,int b)
    121 {
    122     if(dep[a]<dep[b]) swap(a,b);
    123     
    124     for(int i=10;i>=0;i--)
    125     if(dep[f[i][a]]>=dep[b]) a=f[i][a];
    126     
    127     if(a==b) return b;
    128 
    129     for(int i=10;i>=0;i--)
    130     if(f[i][a]!=f[i][b])
    131     a=f[i][a],b=f[i][b];
    132     
    133     return f[0][a];
    134 }
    135 
    136 ll getv(int a,int b)
    137 {
    138     if(dep[a]<dep[b]) swap(a,b);
    139     
    140     ll res=-INF;
    141     
    142     int lca=getLCA(a,b);
    143     
    144     if(lca==a) res=v[b];
    145     else if(lca==b) res=v[a];
    146     else res=max(v[a],v[b]);
    147     
    148     for(int i=10;i>=0;i--)
    149     if(dep[f[i][a]]>dep[lca])
    150     res=max(res,mx[i][a]),a=f[i][a];
    151 
    152     for(int i=10;i>=0;i--)
    153     if(dep[f[i][b]]>dep[lca])
    154     res=max(res,mx[i][b]),b=f[i][b];
    155     
    156     return res;
    157 }
    158 
    159 
    160 int main()
    161 {
    162     
    163     freopen("in.txt","r",stdin);
    164     freopen("out.txt","w",stdout);
    165     
    166     n=getint();
    167     m=getint();
    168     for(int i=0;i<m;i++)
    169     E[i].a=getint()-1,
    170     E[i].b=getint()-1,
    171     E[i].v=getll();
    172     
    173     //Kruskal
    174     for(int i=0;i<m;i++) p[i]=i;
    175     stable_sort(p,p+m,cmp);
    176     INIT(n+1);
    177     ll cres=0;
    178     int tot=0;
    179     for(int i=0;i<m;i++)
    180     if(findf(E[p[i]].a)!=findf(E[p[i]].b))
    181     {
    182         con(E[p[i]].a,E[p[i]].b);
    183         addedge(E[p[i]].a,E[p[i]].b,E[p[i]].v);
    184         E[p[i]].used=true;
    185         cres+=E[p[i]].v;
    186         tot++;
    187     }
    188     
    189     ll res=INF;
    190     if(tot!=n-1) cres=-1;
    191     else
    192     {
    193         //second generated tree
    194         f[0][0]=0;
    195         curd=0;
    196         DFS(0,0);
    197         gen();
    198         
    199         for(int i=0;i<m;i++)
    200         if(!E[i].used && E[i].a!=E[i].b)
    201         {
    202             ll rk=getv(E[i].a,E[i].b);
    203             res=min(res,cres-rk+E[i].v);
    204         }
    205     }
    206     
    207     if(res>=INF/10) res=-1;
    208     
    209     printf("Cost: %I64d
    Cost: %I64d
    ",cres,res);
    210     
    211     return 0;
    212 }
    View Code

    很久很久以前写的,但是一开始WA了.....错在哪呢.....

    变量名打错,n打成m! 倍增的时候dep[lca]写成lca! shenmegui.........

    最终A了.....不是很快的样子.....

     

     

    ..

  • 相关阅读:
    第7.12节 可共享的Python类变量
    (独孤九剑)--MySQL入门
    (独孤九剑)--错误处理
    PHP图像函数
    (独孤九剑)--图像处理
    (独孤九剑)--文件上传
    (独孤九剑)--文件系统
    (独孤九剑)--正则表达式
    (独孤九剑)--数组与数据结构
    PHP填坑
  • 原文地址:https://www.cnblogs.com/DragoonKiller/p/4551321.html
Copyright © 2020-2023  润新知