链接: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∑ndis(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∑ndis(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;
}