版权声明:copy right https://blog.csdn.net/qq_43521140/article/details/90542930
Source
题目大意:
给你n个点,以及每个点的权值ai。连接任意两点之间的花费为ax + ay。
另给出额外m条边的花费,问你要使n个点连通的最少总花费。
思路:
我们容易发现,在不考虑额外给出的m条特殊边的情况下,原图的最少总花费方案为每一个点都向权值最小顶点连一条边。而此题我们只需要再将m条额外边加入边集,对共有(n-1)+ m 条边的边集使用最小生成树算法即可求解。
ACODE:
//7777777
#include<stdio.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-5;
const int MXN = 1e2 + 7;
const int MXM = 1e4 + 7;
const int MX = 2e5 + 7;
const int maxbit = 18;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int pre[MX];
int n,m;
struct chr1s
{
int id;
ll v;
inline bool operator <(const chr1s & x){
return v < x.v;
}
}val[MX << 1];
struct node
{
int u,v;
ll w;
}e[MX << 1];
void init()
{
for(int i = 1;i <= n;++i)
{
pre[i] = i;
}
}
int find(int x)
{
if(pre[x] == x) return x;
return pre[x] = find(pre[x]);
}
bool same(int x,int y)
{
return find(x) == find(y);
}
void unionset(int x,int y)
{
int f1 = find(x);
int f2 = find(y);
if(f1 == f2) return ;
pre[f1] = f2;
}
bool cmp(node a,node b)
{
return a.w < b.w;
}
ll kruskal()
{
int cont = 0;
ll ans = 0;
init();
sort(e+1,e+1+m,cmp);
for(int i = 1;i <= m;++i){
if(same(e[i].u,e[i].v)) continue;
unionset(e[i].u,e[i].v);
ans += e[i].w;
cont++;
if(cont == n-1) break;
}
return ans;
}
int main()
{
#ifdef local
freopen("Input_File.txt","r",stdin);
freopen("Output_File.txt","w",stdout);
#endif
cin >> n >> m;
for(int i = 1;i <= n;++i)
{
cin >> val[i].v;
val[i].id = i;
}
for(int i = 1;i <= m;++i){
cin >> e[i].u >> e[i].v >> e[i].w;
}
sort(val+1,val+1+n);
for(int i = 2;i <= n;++i){
e[++m].u = val[1].id;
e[m].v = val[i].id;
e[m].w = val[1].v + val[i].v;
}
ll ans = kruskal();
cout << ans << endl;
return 0;
}