• 修路方案(次小生成树)


    修路方案

    时间限制:3000 ms  |  内存限制:65535 KB
    难度:5
     
    描述

    南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。

    现在已经知道哪些城市之间可以修路,如果修路,花费是多少。

    现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。

    但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧。

     
    输入
    第一行输入一个整数T(1<T<20),表示测试数据的组数 每组测试数据的第一行是两个整数V,E,(3<V<500,10<E<200000)分别表示城市的个数和城市之间路的条数。数据保证所有的城市都有路相连。 随后的E行,每行有三个数字A B L,表示A号城市与B号城市之间修路花费为L。
    输出
    对于每组测试数据输出Yes或No(如果存在两种以上的最小花费方案则输出Yes,如果最小花费的方案只有一种,则输出No)
    样例输入
    2
    3 3
    1 2 1
    2 3 2
    3 1 3
    4 4
    1 2 2
    2 3 2
    3 4 2
    4 1 2
    样例输出
    No
    Yes
    题解:让找是否存在多个最小生成树;枚举每条不在最小生成树中的边,添加这条边到树中,形成一个环,再删除环中不是这条边的最大边;看是否与最小生成树的权值和相等;存在就是yes
    大神的解释:

    解题思路:花费最少且任意两个城市能够相同,则说明要求最小生成树。而题目中问是否存在另外一种方案,达到

    最小生成树的效果,所以可以采用次小生成树

    常用的一种方法就是在求出最小生成树的基础上进行添加边

    具体实现:先用prim算法求出最小生成树,并且统计任意一点到其他各点的路径上的最大边权。然后添加改生成树上没有的边(u,v),添加一条边后就会形成环,

    然后删除该环中权值大二大的边(即除(u,v)之外的最大权值的边),然后再次统计此时的的费用,如果和最小生生成树的费用相同,则说明存在另外一种方案。

    其中:

    mp!=-1代表不在最小生成树中的边,mx[i][j]代表i到j的最大边,主判断sum-mx[i][j]+mp[i][j]==sum

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<vector>
    using namespace std;
    const int INF=0x3f3f3f3f;
    #define mem(x,y) memset(x,y,sizeof(x))
    #define SI(x) scanf("%d",&x)
    #define PI(x) printf("%d",x)
    typedef long long LL;
    const int MAXN=520;
    int mp[MAXN][MAXN];
    int mx[MAXN][MAXN];
    int vis[MAXN];
    int N,sum;
    vector<int>vec;
    void prim(int sx){
        mem(vis,0);
        vis[sx]=1;
        vec.push_back(sx);
        int u,v;
        while(vec.size()<N){
            int temp=INF;
            for(int i=0;i<vec.size();i++){
                int x=vec[i];
            //    printf("%d
    ",x);
                for(int j=1;j<=N;j++){
                    
                    if(!vis[j]&&mp[x][j]!=-1){
                        if(temp>mp[x][j]){
                            temp=mp[x][j];
                            u=x;
                            v=j;
                        //    printf("u=%d v=%d
    ",u,v);
                        }
                    }
                }
            }
            for(int i=0;i<vec.size();i++){
                int x=vec[i];
            //    printf("u=%d v=%d
    ",u,v);
                if(mx[x][u]<mp[u][v])mx[x][v]=mx[v][x]=mp[u][v];
                else mx[x][v]=mx[v][x]=mx[x][u];
                
            }
            vec.push_back(v);
            vis[v]=1;
            sum+=mp[u][v];
            mp[u][v]=mp[v][u]=-1;
            //printf("%d %d %d
    ",u,v,vec.size());
        }
    }
    int main(){
        int E,T;
        SI(T);
        int a,b,c;
        while(T--){
            mem(mp,-1);mem(mx,-1);
            SI(N);SI(E);
            while(E--){
                scanf("%d%d%d",&a,&b,&c);
                    mp[a][b]=mp[b][a]=c;
                    mx[a][b]=mx[b][a]=c;
            }
            sum=0;
            vec.clear();
            prim(1);
            bool ans=false;
            for(int i=1;i<=N;i++){
                if(ans)break;
                for(int j=1;j<=N;j++){
                    if(mp[i][j]!=-1){
                        if(sum-mx[i][j]+mp[i][j]==sum){
                            ans=true;break;
                        }
                    //    else printf("mx[%d][%d]=%d
    ",i,j,mx[i][j]);
                    }
                }
            }
            if(ans)puts("Yes");
            else puts("No");
        }
        return 0;
    }
  • 相关阅读:
    带你正确的使用List的retainAll方法求交集
    Java URL
    如何正确的创建线程
    小贾漫谈——Java反射
    二、定时器的应用
    网络获取json数据并解析
    异步消息处理机制Handler
    手机安全卫士——Splash总结
    click事件触发也有失灵的时候?
    一张图看透微信公众号、企业号、小程序
  • 原文地址:https://www.cnblogs.com/handsomecui/p/5236122.html
Copyright © 2020-2023  润新知