旅行(构造+最大生成树)

链接:https://ac.nowcoder.com/acm/contest/7329/C
来源:牛客网
 

题目描述

DK 有一个无向图 G,这个无向图有 n 个点 m 条边
你需要确定一个大小为 n 的排列 a,使 ∑i=2ndis⁡(ai−1,ai)\sum\limits_{i=2}^n \operatorname{dis}(a_{i-1},a_i)i=2∑n​dis(ai−1​,ai​) 最大,求这个最大值
dis⁡(u,v)\operatorname{dis}(u,v)dis(u,v) 表示从 u 到 v 的路径的中最短的边的边权,若有多条路径,则选令 dis⁡(u,v)\operatorname{dis}(u,v)dis(u,v) 最大的路径

输入描述:

 

第一行两个正整数 n,m

接下来 m 行,每一行三个正整数 u,v,w 表示 u,v 之间有一条长度为 w 的边

输出描述:

仅一行,表示最大的 ∑i=2ndis⁡(ai−1,ai)\sum\limits_{i=2}^n \operatorname{dis}(a_{i-1},a_i)i=2∑n​dis(ai−1​,ai​)

示例1

输入

复制2 1 1 2 3

2 1
1 2 3

输出

复制3

3

说明

很显然,1,2 或者 2,1 都是合法的

备注:

对于 100%100\%100% 的数据,1≤n,m≤5×1051 \leq n,m \leq 5 \times 10^51≤n,m≤5×105,1≤u,v≤n1\leq u,v\leq n1≤u,v≤n,1≤w≤1091 \leq w \leq 10^91≤w≤109,保证图联通

思路:开始时贪心去考虑,能不能使最终的每一条都是边权最大的数字。然后先画好一些样例,发现总是能构造出来的。

比如:

4 5
1 2 3
1 3 5
2 3 4
3 4 8
2 4 2
通过 1 4 3 2就能构造出 5+4+8的总边权值。

所以直接最大生成树。可以取负去算,也可以反着排序。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
typedef long long ll; 
const int maxn=5e5+1000;
struct Edge
{
	int u,v,w;
}edge[maxn];
ll fa[maxn],n,m,ans,eu,ev,cnt;
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}
ll find(int x)
{
    while(x!=fa[x]) x=fa[x]=fa[fa[x]];
    return x;
}
void kruskal()
{
    sort(edge,edge+m,cmp);
    for(ll i=0;i<m;i++)
    {
        eu=find(edge[i].u), ev=find(edge[i].v);
        if(eu==ev)
        {
            continue;
        }
        ans+=edge[i].w;
        fa[ev]=eu;
        if(++cnt==n-1)
        {
            break;
        }
    }
}
int main()
{
	cin.tie(0);std::ios::sync_with_stdio(false);
    cin>>n>>m;
    for(ll i=1;i<=n;i++)
    {
        fa[i]=i;
    }
    ll sum=0;
    for( ll i=0;i<m;i++)
    {
    	cin>>edge[i].u>>edge[i].v>>edge[i].w;
    	edge[i].w=-1.0*edge[i].w;
    }
    kruskal();
    cout<<-ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108548169