思路:给定一个顶点,以这个顶点bfs扩展所有能到的点,求这些点的最小生成树
关键在对边的排序,边的排序不能像一般的最小生成树一样只对树的边权大小进行排序,这里的边都是有方向的,比如看下图的这个例子
假如这个图是做完bfs后扩展出来的图,图上面的每一个点都是要遍历到的,不同的排序方法就会得到不同的结果。 只对边权排序:权值和为5*1+4,结果是9 先排高度在排边权:5+4+4*1,结果是13 但在这里第一个结果相当于没有走到第2层的左边的点,因为滑雪只能从高往低走,第二层左边那个点是由边权为1的更低点扩展出来的,这样是不符合题意的。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int N=1e5+10,M=2e6+10;
int f[N];
bool st[N];
int n,m,cnt,u;
vector<int>v[N];
int h[N];
int find(int x)
{
if(x!=f[x])
f[x]=find(f[x]);
return f[x];
}
struct nod
{
int a,b,c;
int w;
}e[M];
bool cmp(nod a,nod b)
{
if(a.w==b.w)
return a.c<b.c;
else
return a.w>b.w;
}
void bfs()
{
queue<int>q;
q.push(1);
st[1]=1;
cnt++;
while(q.size())
{
int t=q.front();
q.pop();
for(int i=0;i<v[t].size();i++)
{
if(!st[v[t][i]])
{
q.push(v[t][i]);
st[v[t][i]]=true;
cnt++;
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
f[i]=i;
}
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(h[a]>=h[b]) e[++u]={a,b,c,h[b]} ,v[a].push_back(b);
if(h[b]>=h[a]) e[++u]={b,a,c,h[a]} ,v[b].push_back(a);
}
sort(e+1,e+u+1,cmp);
long long sum=0;
bfs();
for(int i=1;i<=u;i++)
{
int a=e[i].a,b=e[i].b,c=e[i].c;
a=find(a),b=find(b);
if(a!=b&&st[a]&&st[b])
{
f[a]=b;
sum+=c;
}
}
cout<<cnt<<' ';
cout<<sum<<endl;
return 0;
}