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

      求次小生成树的步骤是:

        1、求出最小生成树MST,用一个矩阵maxe[u][v]记录在MST中连接u-v的路径中权值最大的边.

        2、枚举所有不在T中的边u-v,加入边u-v,删除权值为max[u][v]的边,不断枚举找到次小生成树.

      由于邻接矩阵建图无法储存平行边(重边),我们在建图的时候都是取当前最小值。所以用prim做的话,很可能出错。但是prim也是有市场的,当没有平行边,并且定点数比较少的时候,用prim就有优势。如果有平行边,就必须用kruskal。用链式前向星建图。

      下面是两个模版,时间复杂度是不同的。不过,貌似时间复杂度相差不大。最大的区别还是平行边。

      可以用该模版试试poj1679

    //Kruskal
    //时间复杂度 O(mlogm + n^2) const int N=1010,M=100010,INF=0x3f3f3f3f; int f[N],r[N]; int Find(int x) { if(x==f[x]) return x; return f[x]=Find(f[x]); } void Link(int x,int y) { int a=Find(x), b=Find(y); if(a!=b) { f[b]=a; r[a]+=r[b]; } } struct node { int u,v,w; bool select; }edge[M]; bool cmp(const node &a, const node &b) { if(a.w!=b.w) return a.w<b.w; if(a.u!=b.u) return a.u<b.u; return a.v<b.v; } struct node1 { int to,next; }e[N]; int cnt,tot,head[N],en[N],maxe[N][N]; //e的边数、头结点、尾结点、两点在mst中的最大边 void Kruskal(int n,int m) { int k=0, i,j,t; for(cnt=0;cnt<n;cnt++) { e[cnt].to=cnt+1; e[cnt].next=head[cnt+1]; en[cnt+1]=cnt; head[cnt+1]=cnt; } sort(edge,edge+m,cmp); for(i=0;i<m;i++) { if(k==n-1) break; if(edge[i].w<0) continue; int a=Find(edge[i].u), b=Find(edge[i].v); if(a!=b) { for(j=head[a];j!=-1;j=e[j].next){ for(t=head[b];t!=-1;t=e[t].next){ int u=e[j].to, v=e[t].to; maxe[u][v]=maxe[v][u]=edge[i].w; } } e[en[b]].next=head[a]; en[b]=en[a]; Link(a,b); k++; edge[i].select=1; } } } void addedge(int u,int v,int w) { edge[tot].u=u;edge[tot].v=v;edge[tot].w=w;tot++; } void init() { tot=0; memset(head,-1,sizeof(head)); memset(en,-1,sizeof(en)); for(int i=0;i<N;i++){ edge[i].select=0; f[i]=i; r[i]=1; } } int main() { //freopen("test.txt","r",stdin); int mst,secmst; Kruskal(n,m); mst=0; for(i=0;i<m;i++){ if(edge[i].select) mst+=edge[i].w; } secmst=INF; for(i=0;i<m;i++){ if(!edge[i].select) secmst=min(secmst,mst+edge[i].w-maxe[edge[i].u][edge[i].u]]); } return 0; }

      prim,时间复杂度是O (2 n^2) 

    const int maxn=1100,INF=0x3f3f3f3f;
    int dist[maxn],Map[maxn][maxn],pre[maxn],maxe[maxn][maxn];
    //向外延伸的最短边长,记录图信息,记录连接信息,最长边
    bool vis[maxn];//1表示点已经在树的,0表示点在树外
    bool f[maxn][maxn];//存在边为1,用过为0
    int n,m;//顶点数目
    int Prim()
    {
        int i,j,k,Min,ans=0;
        memset(vis,0,sizeof(vis));
        memset(f,0,sizeof(f));
        memset(maxe,0,sizeof(maxe));
        for(i=2;i<=n;i++)
        {
            dist[i]=Map[1][i];
            pre[i]=1;
        }
        dist[1]=0;
        vis[1]=1;
        pre[1]=0;
        for(i=1;i<n;i++)
        {
            Min=INF;
            k=0;
            for(j=1;j<=n;j++)
            {
                if(!vis[j]&&dist[j]<Min)
                {
                    Min=dist[j];
                    k=j;
                }
            }
            if(Min==INF) return -1;//G不连通
            vis[k]=1;
            ans+=Min;
            f[pre[k]][k] = f[k][pre[k]]=1;
            for(j=1;j<=n;j++)
            {
                if(vis[j]) maxe[k][j]=maxe[j][k]=max(maxe[j][pre[k]],dist[k]);
                if(!vis[j]&&dist[j]>Map[k][j])
                {
                    dist[j]=Map[k][j];
                    pre[j]=k;
                }
            }
        }
        return ans;
    }
    void init()
    {
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
            {
                if(i==j)Map[i][j]=0;
                else Map[i][j]=INF;
            }
    }
  • 相关阅读:
    【Git】Git 学习笔记(一)
    【工程 Shell】Shell 学习(一)
    Vue 使用 Antd 简单实现左侧菜单栏和面包屑功能
    GoF的23种设计模式的功能
    ASP 对数据库的操作
    注册表修改USB状态(开与关)
    EXE文件关联修复
    CentOS8安装Docker
    GoogleEarth无法连接服务器解决方法
    【转】Qt 实现的拷贝 文件/文件夹 的函数
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/3949996.html
Copyright © 2011-2022 走看看