• POJ


    题意:就是判断图的最小生成树是否唯一,即求其最小生成树(MST)和次小生成树。

    虽然是一道模板题,更重要的是理解求次小生成树的过程。求次小生成树建立在Prim算法的基础上。可以确定的是,次小生成树肯定是由最小生成树删去一条边再加上一条边得到。那么我们应该删去哪条边再加上哪条边呢?假设两点u,v之间有一条边且这条边不在MST中,那么可以尝试加上这条边。但是加上这条边以后会出现环,则一定要去掉回路上的一条边,这条边应该选择回路上权值最大的那条边(毕竟权值要求尽量小)。尝试对每对点对进行上述操作,那么最小的那个结果就是次小生成树。

    算法中用一个二维数组path[u][v]维护已经确定的最小生成树上的每对结点之间的路径上,权值最大的那条边,而这个维护的过程就是在Prim算法中增加的部分。

    当求出最小生成树以后,我们也得到了完整的path数组。然后枚举任意两个点对u和v,求出min(MST-path[u][v]+G[u][v]),结果就是次小生成树的值。

    邻接矩阵实现:

    #include<iostream>
    #include<stdio.h>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn =1e2+5;
    const int INF = 0x3f3f3f3f;
    int G[maxn][maxn],dist[maxn];
    int path[maxn][maxn];       //记录生成树上每对结点得最大边权
    bool used[maxn][maxn];
    int pre[maxn];
    bool vis[maxn];
    struct Edge{
        int to,val;
    };
    
    void init(int N)
    {
        for(int i=0;i<=N;++i){
            for(int j=i;j<=N;++j){
                G[i][j]=G[j][i]=INF;
            }
        }
    }
    
    void AddEdge(int u,int v,int val)
    {
        G[v][u]=G[u][v]=val;
    }
    
    
    int prim(int N)
    {
        int Mst=0;
        memset(used,0,sizeof(used));
        memset(path,0,sizeof(path));
        memset(vis,0,sizeof(vis));
        vis[1]=true;                    //从1开始
        
        for(int i=1; i<=N; ++i){
            dist[i]=G[1][i];
            pre[i]=1;
        }
    
        for(int i=1;i<N;++i){
            int u=-1;
            for(int j=1;j<=N;++j){
                if(!vis[j] && (u==-1 || dist[j]<dist[u]))
                    u=j;
            }        
            used[u][pre[u]]= used[pre[u]][u]=true;
            vis[u]=true;
            Mst+=G[pre[u]][u];
            for(int j=1;j<=N;++j){
                if(vis[j] && j!=u){     //若j已经被访问且不是u本身,更新点对u和j的path
                    path[u][j]=path[j][u]=max(path[j][pre[u]],dist[u]); 
                }
                else if(!vis[j]){       //若j没被访问,更新dist
                    if(dist[j]>G[u][j]){
                        dist[j]=G[u][j];
                        pre[j]=u;
                    }
                }
            }
        }
        return Mst;
    }
    
    int main()
    {
        int T,N,M,u,v,tmp;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&N,&M);
            init(N);
            for(int i=0;i<M;++i){
                scanf("%d%d%d",&u,&v,&tmp);
                AddEdge(u,v,tmp);
                AddEdge(v,u,tmp);
            }
            int Mst=prim(N);
            int res=INF;
            for(int i=1; i<=N; ++i){
                for(int j=1; j<=N; ++j){
                    if(i!=j && !used[i][j]){
                        res=min(res,Mst+G[i][j]-path[i][j]);        //检查每对结点
                    }
                }
            }
    
            if(res==Mst)printf("Not Unique!
    ");
            else    printf("%d
    ",Mst);
        }
        return 0;
    }
    为了更好的明天
  • 相关阅读:
    三种基本排序算法
    sourcetree push限制大小
    移动端布局注意事项
    margin-top 实效问题
    布局方式
    web前端开发工程师
    eScript 简记
    Siebel script for Pre Events
    Siebel Performance for Script <1>
    Siebel Presumed Child Property Set
  • 原文地址:https://www.cnblogs.com/xiuwenli/p/9349558.html
Copyright © 2020-2023  润新知