#E. 滑雪与时间剂
- 题意
有N个点,每个点有自己的高度,只能从高处到低处
如果一条边两边高度不同,则路为单向,否则为双向
他可以随时回到之前的任意一点,从1点出发,在满足到的点尽可能多的情况下求最小距离
- 分析
对于任意点来说,只能从比他更高(或一样高)的点走到
所以按照高度作为第一关键字排序,再跑最小生成树即为答案
- 细节
先要跑一遍DFS,确定可到个数后再跑最小生成树
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,h[5000000],vis[5000000],cnt,ans,fa[5000000];
ll head[5000000],tot,toto;
struct nood{
ll v;
ll w;
ll lz;//来自哪里
ll nxt;
}es[5000000];
struct nood1{
ll x;
ll y;
ll w;
}es1[5000000];
void adde(ll x,ll y,ll z){
es[++tot].v=y,es[tot].w=z,es[tot].lz=x,es[tot].nxt=head[x],head[x]=tot;
}
void dfs(ll x){
vis[x]=1;
cnt++;
for(int i=head[x];i;i=es[i].nxt){
ll v=es[i].v;
if(!vis[v]){
dfs(v);
}
}
}
int find(int x){
if(fa[x] == x)
return x;
return fa[x] = find(fa[x]);
}
void merge(ll x,ll y){
ll xx=find(x);
ll yy=find(y);
if(xx!=yy){
fa[xx]=yy;
}
}
bool cmp(nood1 a,nood1 b){
if(h[a.y]==h[b.y]){
return a.w<b.w;
}
return h[a.y]>h[b.y];
}
void kru(){
for(int i=1;i<=n;i++){
fa[i]=i;
}
sort(es1+1,es1+toto+1,cmp);
for(int i=1;i<=toto;i++){
if(find(es1[i].x)!=find(es1[i].y)){
ans+=es1[i].w;
//fa[find(es1[i].x)]=fa[es1[i].y];
merge(es1[i].x,es1[i].y);
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>h[i];
}
ll x,y,z;
for(int i=1;i<=m;i++){
cin>>x>>y>>z;
if(h[x]>=h[y]){
adde(x,y,z);
}
if(h[x]<=h[y]){
adde(y,x,z);
}
}
dfs(1);
for(int i=1;i<=tot;i++){
if(vis[es[i].lz]&&vis[es[i].v]){
es1[++toto].x=es[i].lz;
es1[toto].y=es[i].v;
es1[toto].w=es[i].w;
//cout<<es1[toto].w<<" "<<es1[toto].x<<" "<<es1[toto].y<<endl;
}
}
kru();
cout<<cnt<<" "<<ans;
}
标签:int,ll,tot,fa,时间,滑雪,5000000,es
From: https://www.cnblogs.com/Misty-post/p/18440679