题目
题意:
给定n个点,每个点都有权值a[i],给x,y加边的代价是两点的权值相加。在给出m条规则x,y,v,也可以利用规则对x,y加边,花费为v。要求将这些点连起来形成树的最小花费代价。
分析:
显然就是一棵最小生成树,但是由于点数太多,我们不能考虑所有的边。分析一下可以知道其实每个点要使用第一条规则的话,必然是与权值最小的点相连。所以我们只需要考虑权值最小的点与别的点的边和规则2给出的边,跑最小生成树即可。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int parent[200005];
struct edge{
int x,y;
ll v;
edge(int a,int b,ll c)
{
x = a;
y = b;
v = c;
}
bool operator<(const edge&e)const
{
return v < e.v;
}
};
vector<edge> a;
ll v[200005];
int find(int p)
{
if( p == parent[p] ) return p;
return parent[p] = find(parent[p]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
ll ans = 0;
int begin;
ll minx = 1e18;
for (int i = 1; i <= n; i++)
{
cin >> v[i];
parent[i] = i;
if( minx > v[i] )
{
minx = v[i];
begin = i;
}
}
for (int i = 1; i <= m; i++)
{
int x,y;
ll v;
cin >> x >> y >> v;
a.push_back(edge(x,y,v));
}
for (int i = 1; i <= n; i++)
{
if( i == begin ) continue;
a.push_back(edge(begin,i,v[begin]+v[i]));
}
sort(a.begin(),a.end());
for (int i = 0; i < a.size(); i++)
{
int rootx = find(a[i].x);
int rooty = find(a[i].y);
if( rootx != rooty )
{
ans += a[i].v;
parent[rootx] = rooty;
}
}
cout << ans << '\n';
return 0;
}