• UVA10600 次小生成树


    题目链接:https://vjudge.net/problem/UVA-10600

    题意:叫我们求出最小生成树的边权之和 和次小生成树的边权之和。

    思路:我们可以先求出最小生成树,这个不难,如果要求次小生成树,那么我们肯定是要在最小生成树里面去掉一条边(假设是a),这样就变成两颗生成树了,我们就还要找一条边(假设是b)把这两颗树连接。这里我们需要满足的就是b-a最小(b一定大于a),这样找到的生成树就是次小生成树了是吧。

    关键就是怎么更快的找到b和a这两条边的权值,使b-a最小。因为现在已经是最小生成树了,我们如果连接任意两点,那么根据树的性质,就一定会形成一个环了,那么我们肯定是去掉这个环里面除去边b之外的所有边里面权值最大的边,这样才可以在选择连接边b的情况下使重新生成的树的权值最小。然按照这个思路我们枚举每两点,就可以求出次小生成树了。

    现在我们就要求出在最小生成树上每两点之间最大的边权,我们在这里用动态规划来实现,用maxx[i][j]来记录点i和点j之间最大的边权,在用prime算法来求最小生成树的时候,我们每增加一个点到树中,就求出这个点和已经加入树里面的所有点之间的maxx数组值,这里还要记录每个点的前驱,(假设点u的前驱就是pre[u],那么pre[u]就是在生成树里面和点u直接相连的并且在点u之前加入树中的点),那么假设现在我把点u加到树上,点j在点u之前就已经加在树上了,现在我要求出maxx[j][u],递推公式就是

    maxx[j][u]=max(maxx[j][pre[u]],map[u][pre[u]]);也就是max(pre[u]和点j的maxx数组值,pre[u]和点u直接相连的边的权值);

    看代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<set>
    #include<cstdio>
    #include<string>
    #include<deque> 
    using namespace std;
    typedef long long LL;
    #define eps 1e-8
    #define INF 0xffffff
    #define maxn 105
    int n,m,k,t,ans1,ans2,sum; 
    int check[maxn][maxn],map[maxn][maxn],pre[maxn],vis[maxn],maxx[maxn][maxn],dis[maxn];
    //check[i][j]表示最小生成树里i和j是否直接相连,map[i][j]记录i和j的边权
    //pre[u]记录点u的前驱,maxx[i][j]记录点i和点j之间路径上权值最大的边 
    void init(){
        memset(check,0,sizeof(check));
        memset(pre,0,sizeof(pre));
        memset(vis,0,sizeof(vis));
        memset(maxx,0,sizeof(maxx));
        for(int i=1;i<n;i++){
            for(int j=i+1;j<=n;j++){
                map[i][j]=map[j][i]=INF;
            }
        }
        sum=0;//记录最小生成树的边权和 
        ans1=ans2=INF;
    }
    void prime(){
        for(int i=1;i<=n;i++)
        dis[i]=INF;
        dis[1]=0;
        for(int i=1;i<=n;i++){
            int u,min1=INF;
            for(int j=1;j<=n;j++){
                if(!vis[j]&&dis[j]<min1){
                    min1=dis[j];
                    u=j;
                }
            }
            vis[u]=1;
            sum+=min1;
            check[pre[u]][u]=check[u][pre[u]]=1;//把走过的边标记
            for(int j=1;j<=n;j++){
                if(vis[j]&&j!=u){//用动态规划来计算点u和点j的maxx数组值 
                    maxx[j][u]=maxx[u][j]=max(maxx[pre[u]][j],map[pre[u]][u]);
                }
                if(!vis[j]&&dis[j]>map[u][j]){
                    dis[j]=map[u][j];
                    pre[j]=u;
                }
            } 
            
        }
    }
    void second(){//求次小生成树的权值和
        for(int i=1;i<n;i++){
            for(int j=i+1;j<=n;j++){
                if(map[i][j]!=INF&&check[i][j]==0){
                    ans2=min(ans2,sum+map[i][j]-maxx[i][j]);//去掉一条边,增加一条边 
                }
            }
        }
    }
    int main()
    {
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            init();
            int u,v,w;
            for(int i=1;i<=m;i++){
                scanf("%d%d%d",&u,&v,&w);
                map[u][v]=map[v][u]=min(map[u][v],w);
            }
            prime();
            ans1=sum;
            second();
            printf("%d %d
    ",ans1,ans2);
        }
        return 0;
    }
  • 相关阅读:
    高兴啊~~新博皮诞生咯~~
    不同的手机用户被表现
    这是荷塘月色另外的一种风格代码,要的拿。。。。记得禁止默认CSS
    开始做新博皮!@
    哎,回来拉
    漂亮!正常咯~~!~
    郁闷,垃圾CSS!
    新开始,新起航。。
    Debug!Debug!Debug!
    Dubbo源码学习总结系列一 总体认识
  • 原文地址:https://www.cnblogs.com/6262369sss/p/10072834.html
Copyright © 2020-2023  润新知