zoukankan      html  css  js  c++  java
  • UVA 10600 ACM Contest and Blackout (次小生成树)

    题意:

      求图中的最小生成树和次小生成树。

    题解:

      

    一种容易想到的方法是枚举删除最小生成树上的边,再求最小生成树。用kruskal这种算法的复杂度为O(n*elog2e),当图比较稠密时,复杂度接近O(n^3)。

        但有一种更简单的方法:先求最小生成树T,枚举添加不在T中的边,则添加后一定会形成环。找到环上边值第二大的边(即环中属于T中的最大边),把它删掉,计算当前生成树的权值,取所有枚举修改的生成树的最小值,即为次小生成树。

        这种方法在实现时有更简单的方法:首先求最小生成树T,然后从每个结点u遍历最小生成树T,用一个二维数组max[u][v]记录结点u到结点v的路劲上边的最大值(即最大边的值)。然后枚举不在T中的边(u,v),计算T- max[u][v] + w(u,v)的最小值,即为次小生成树的权值。显然,这种方法的时间复杂度为O(n^2 + e)。

        可见,第二种算法将原来的时间复杂度O(n^3)提高到了O(n^2)。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=105,INF=0x3f3f3f3f;
    int n,m;
    int pre[maxn],mincost[maxn];
    bool vis[maxn],used[maxn][maxn];
    int cost[maxn][maxn],path[maxn][maxn];
    void init()
    {
        memset(pre,-1,sizeof(pre));
        memset(path,0,sizeof(path));
        memset(vis,false,sizeof(vis));
        memset(used,false,sizeof(used));
        for(int i=1;i<=n;i++)
            mincost[i]=INF;
    }
    int prim()
    {
        init();
        int res=0;
        mincost[1]=0;
        while(1)
        {
            int v=-1;
            for(int u=1;u<=n;u++)
                if(!vis[u]&&(v==-1||mincost[u]<mincost[v]))
                    v=u;
            if(v==-1)
                break;
            if(pre[v]!=-1)
            {
                used[pre[v]][v]=used[v][pre[v]]=true;
                for(int u=1;u<=n;u++)
                {
                    if(vis[u])
                        path[u][v]=path[v][u]=max(path[u][pre[v]],cost[v][pre[v]]);
                }
            }
            vis[v]=true;
            res+=mincost[v];
            for(int u=1;u<=n;u++)
            {
                if(mincost[u]>cost[u][v])
                {    
                    mincost[u]=cost[u][v];
                    pre[u]=v;
                }
            }
        }
        return res;
    }
    int sec_mst(int res)
    {
        int ans=INF;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(!used[i][j])
                    ans=min(ans,res-path[i][j]+cost[i][j]);
            }
        return ans;
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            init();
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    cost[i][j]=INF;
            for(int i=0;i<m;i++)
            {
                int a,b,c;
                cin>>a>>b>>c;
                cost[a][b]=cost[b][a]=c;
            }
            int ans=prim();
            printf("%d %d
    ",ans,sec_mst(ans));
        }
        return 0;
    }
  • 相关阅读:
    Nginx调优
    Nginx的压缩配置
    【进阶 6-1 期】JavaScript 高阶函数浅析
    个人总结的一个中高级Java开发工程师或架构师需要掌握的一些技能
    Java程序猿跳槽应该学哪些方面的技术!
    xamarin学习之路 例一、嵌入网页
    xamarin学习之路 一、vs2015 环境搭建
    xamarin 学习异常问题解决方法
    js 替换字符串 replace函数运用
    76Byte让你的JQuery更快
  • 原文地址:https://www.cnblogs.com/orion7/p/7400556.html
Copyright © 2011-2022 走看看