修路方案(次小生成树)

修路方案

时间限制: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\n",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\n",u,v);
                    }
                }
            }
        }
        for(int i=0;i<vec.size();i++){
            int x=vec[i];
        //    printf("u=%d v=%d\n",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\n",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\n",i,j,mx[i][j]);
                }
            }
        }
        if(ans)puts("Yes");
        else puts("No");
    }
    return 0;
}

时间: 2024-10-02 18:11:32

修路方案(次小生成树)的相关文章

NYOJ修路方案【次小生成树】

修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输

UVA - 1494 Qin Shi Huang&#39;s National Road System (类次小生成树)

Description During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China -- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally con

NYOJ 118 修路方案

修路方案 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输

修路方案(nyoj)

算法:次小生成树 描述 南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路. 现在已经知道哪些城市之间可以修路,如果修路,花费是多少. 现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少. 但是,南将军说,这个修路方案所拼成的图案很不吉利,想让小工计算一下是否存在另外一种方案花费和刚才的方案一样,现在你来帮小工写一个程序算一下吧. 输入 第一行输入一个整数T(1<T<20),表示测试数据的组数每组测试数据的

HDU4081 Qin Shi Huang&#39;s National Road System【Kruska】【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3979    Accepted Submission(s): 1372 Problem Description During the Warring States Period of ancient China(4

kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一个环,如果还要维护处树的特点 那么就要在这个环上删去一条边,这样他还是树,删掉的边显然是这条链上权值最大边更可能形成次小生成树.那么就有2中方法可以做. 第一种PRIM在prim时候直接可以做出这个从I到J的链上权值最大的值MAX[i][j]; 同时可以用kruskal同样方式标记树边,然后DFS跑

HDU 4081 Qin Shi Huang&#39;s National Road System(最小生成树/次小生成树)

题目链接:传送门 题意: 有n坐城市,知道每坐城市的坐标和人口.现在要在所有城市之间修路,保证每个城市都能相连,并且保证A/B 最大,所有路径的花费和最小,A是某条路i两端城市人口的和,B表示除路i以外所有路的花费的和(路径i的花费为0). 分析: 先求一棵最小生成树,然后枚举每一条最小生成树上的边,删掉后变成两个生成树,然后找两个集合中点权最大的两 个连接起来.这两个点中必然有权值最大的那个点,所以直接从权值最大的点开始dfs. 为了使A/B的值最大,则A尽可能大,B尽可能小.所以B中的边一定

nyoj 修路方案 (判断最小生成树是否唯一)

裸 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 struct node 7 { 8 int x, y, dis; 9 int flag; 10 } a[200010]; 11 12 int cmp(node x, node y) 13 { 14 return x.dis<y.dis; 15 } 16 int father[5

hdu4081 次小生成树变形

http://acm.hdu.edu.cn/showproblem.php?pid=4081 Problem Description During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China ---- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of