P2573 [SCOI2012] 滑雪 —— 生成树
[SCOI2012] 滑雪
题目描述
a180285 非常喜欢滑雪。他来到一座雪山,这里分布着 条供滑行的轨道和 个轨道之间的交点(同时也是景点),而且每个景点都有一编号 和一高度 。
a180285 能从景点 滑到景点 当且仅当存在一条 和 之间的边,且 的高度不小于 。与其他滑雪爱好者不同,a180285 喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。
于是 a18028 5拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是 a180285 滑行的距离)。
请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在 号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入格式
输入的第一行是两个整数 。
接下来一行有 个整数 ,分别表示每个景点的高度。
接下来 行,表示各个景点之间轨道分布的情况。每行三个整数 ,表示编号为 的景点和编号为 的景点之间有一条长度为 的轨道。
输出格式
输出一行,表示 a180285 最多能到达多少个景点,以及此时最短的滑行距离总和。
样例 #1
样例输入 #1
3 3 3 2 1 1 2 1 2 3 1 1 3 10
样例输出 #1
3 2
提示
【数据范围】
对于 的数据,;
对于 的数据,。
对于所有的数据,保证 , ,。
分析
先从1号点出发搜索所有能遍历的点,顺便记下遍历过的边。
以终点的高度为第一关键字从大到小,以边的长度为第二关键字从小到大,对标记的边排序。
前者保证能遍历尽可能多的点,后者保证最小距离。
合并边到新的生成树上即可。
注意同样高度的点建双向边。
#include<bits/stdc++.h> using namespace std; const int N=1e5+100,M=1e6+100; struct edge{int y,n,x;long long z;}e[M<<1],t[M<<1]; int n,m,h[N],f[N]; int tot,cnt,head[N],sum; int dh[N],rec[N],q[M]; bool vis[N]; long long dis; bool cmp(edge a,edge b) { if(h[a.y]==h[b.y])return a.z<b.z; return h[a.y]>h[b.y]; } int fin(int x) { if(f[x]==x)return x; f[x]=fin(f[x]); return f[x]; } void bfs() { int he=1,ta=0; q[++ta]=1;sum=1;vis[1]=1; while(he<=ta) { int u=q[he]; ++he; for(int i=head[u];i;i=e[i].n) { int v=e[i].y; t[++cnt].n=dh[u]; t[cnt].y=v; t[cnt].z=e[i].z; t[cnt].x=u; dh[u]=cnt; if(!vis[v]) { vis[v]=1; ++sum; q[++ta]=v; } } } } void go(int u,int fa,long long len) { bool fl=0; for(int i=dh[u];i;i=t[i].n) { int v=t[i].y; if(v==fa)continue; go(v,u,len+t[i].z); fl=1; } if(!fl)dis+=len; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){f[i]=i;scanf("%d",h+i);} for(int i=1,x,y;i<=m;++i) { long long z=0; scanf("%d%d%lld",&x,&y,&z); if(h[x]<h[y])swap(x,y);// x --> y e[++tot].n=head[x]; e[tot].x=x; e[tot].y=y; e[tot].z=z; head[x]=tot; if(h[x]==h[y]) { e[++tot].n=head[y]; e[tot].x=y; e[tot].y=x; e[tot].z=z; head[y]=tot; } } bfs(); sort(t+1,t+1+cnt,cmp); int num=0; for(int i=1,x,y,fx,fy;i<=cnt;++i) { x=t[i].x; y=t[i].y; fx=fin(x); fy=fin(y); if(fx!=fy) { f[fy]=fx; dis+=t[i].z; ++num; if(num==sum-1)break; } } printf("%d %lld",sum,dis); return 0; }
本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18576236
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具