前言
引用站外地址
调了一个下午终于弄出来了!!!
最近开始毛616的CG当封面偷懒了qwq
题目
查看题面
[SCOI2012] 滑雪
题目描述
a180285 非常喜欢滑雪。他来到一座雪山,这里分布着 m 条供滑行的轨道和 n 个轨道之间的交点(同时也是景点),而且每个景点都有一编号 i (1≤i≤n) 和一高度 hi。
a180285 能从景点 i 滑到景点 j 当且仅当存在一条 i 和 j 之间的边,且 i 的高度不小于 j。与其他滑雪爱好者不同,a180285 喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。
于是 a18028 5拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是 a180285 滑行的距离)。
请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在 1 号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入格式
输入的第一行是两个整数 n,m。
接下来一行有 n 个整数 hi,分别表示每个景点的高度。
接下来 m 行,表示各个景点之间轨道分布的情况。每行三个整数 u,v,k,表示编号为 u 的景点和编号为 v 的景点之间有一条长度为 k 的轨道。
输出格式
输出一行,表示 a180285 最多能到达多少个景点,以及此时最短的滑行距离总和。
样例 #1
样例输入 #1
1 2 3 4 5
| 3 3 3 2 1 1 2 1 2 3 1 1 3 10
|
样例输出 #1
提示
【数据范围】
对于 $ 30% $ 的数据,$ 1 \le n \le 2000 $;
对于 $ 100% $ 的数据,$ 1 \le n \le 10^5 $。
对于所有的数据,保证 $ 1 \le m \le 10^6 $ , $ 1 \le h_i \le 10^9 $ ,$ 1 \le k_i \le 10^9 $。
题解
首先不难想到这是一个最小生成树题目:a180285 从点 1 出发,他希望遍历尽可能多的点且他可以回退,需要求此时代价最小路径的长度。
考虑使用 Kruskal 或 Prim 算法,因为 Kruskal 编码比较简单,遂采用该算法。
因为多个滑雪站之间只有高度较高的才能前往高度较低的站点,即对于任意 G(V,E),当 i,j∈V 时且 hi≥hj 时才存在 (i,j)∈E,所以我们需要根据 hu 和 hv 的关系来确定需要添加的边。
然后我们从起点 1 开始执行 BFS (DFS也可),算出从起点出发最多可以到达的顶点个数 tot 。
为了方便,我开了一个前向星(纠正:因本蒟蒻之前的理解偏差,这并不叫做前向星,叫做存边数组差不多)和一个邻接表分别用于 Kruskal 和 BFS(都是打的 vector
qwq)。
接下来排序并执行 Kruskal。排序需要注意一点:直接根据每一条边的权值 w 排序的贪心策略是错误的,可以考虑这么一种情况:
这是一张图,其中每个节点上面的 vx 表示编号,h:x 表示高度,边上的数字表示权值。如果我们按照边权排序后选择的话,就会选到 (4,3)=1, (1,3)=4 和 (1,2)=4,即上面描红了的边。然而这是无向图,我们就会发现 v1 并不能到达 v4,然而我们要是选择了 (1,4)=11,虽然代价稍大,但是可以保证选到最多的点。
因为高度呈降序排列,前面的点一定可以到达后面的点,所以我们在高度上贪心取最小值即可保证尽可能选到多的点,当然高度一样时肯定也需要取权值较小的。
有几个坑:
坑 1:注意 BFS 时的 vis
数组,处理 Kruskal 时如果 !vis[u]||!vis[v]
时需要跳过(因为无法走到)。
坑 2:建边处理高度时需要同时考虑开的一个前向星和一个邻接表,不能少一个,否则必爆 0 ~ 18。
坑 3:处理 Kruskal 时,如果 cnt==tot-1
即已遍历边数已经形成树形结构时就得 break
了。
那么代码就很简单了(但是注意有很多坑+没看注释导致的CE)
代码
偷懒,所以用了新特性,注意开 C++20以上。
注释版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <bits/stdc++.h> #define int long long using namespace std; int n,m,fa[100005],tot=1,ans,vis[100005],h[100005]; struct node {int x,y,w,h;}; vector<node> star; vector<int> lst[100005]; queue<int> q; inline void add(int u,int v,int w){ if(h[u]>=h[v]) star.push_back({u,v,w,h[v]}), lst[u].push_back(v); if(h[u]<=h[v]) star.push_back({v,u,w,h[u]}), lst[v].push_back(u); } inline int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } signed main(){ ios::sync_with_stdio(0); cin>>n>>m; for(int i=1;i<=n;i++) cin>>h[i],fa[i]=i; for(int i=1,u,v,c;i<=m;i++) cin>>u>>v>>c,add(u,v,c); q.push(1),vis[1]=1; while(!q.empty()){ int u=q.front();q.pop(); for(auto &it:lst[u]) if(!vis[it]) vis[it]=1,tot++,q.push(it); } sort(star.begin(),star.end(),[](node a,node b){ return a.h==b.h?a.w<b.w:a.h>b.h; }); for(int cnt=0;auto it:star){ if(vis[it.x]&&vis[it.y]){ int x=find(it.x),y=find(it.y); if(x==y) continue; fa[x]=y,cnt++,ans+=it.w; if(cnt==tot-1) break; } } cout<<tot<<" "<<ans; return 0; }
|
无注释版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <bits/stdc++.h> #define int long long using namespace std; int n,m,fa[100005],tot=1,ans,vis[100005],h[100005]; struct node {int x,y,w,h;}; vector<node> star; vector<int> lst[100005]; queue<int> q; inline void add(int u,int v,int w){ if(h[u]>=h[v]) star.push_back({u,v,w,h[v]}), lst[u].push_back(v); if(h[u]<=h[v]) star.push_back({v,u,w,h[u]}), lst[v].push_back(u); } inline int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } signed main(){ ios::sync_with_stdio(0); cin>>n>>m; for(int i=1;i<=n;i++) cin>>h[i],fa[i]=i; for(int i=1,u,v,c;i<=m;i++) cin>>u>>v>>c,add(u,v,c); q.push(1),vis[1]=1; while(!q.empty()){ int u=q.front();q.pop(); for(auto &it:lst[u]) if(!vis[it]) vis[it]=1,tot++,q.push(it); } sort(star.begin(),star.end(),[](node a,node b){ return a.h==b.h?a.w<b.w:a.h>b.h; }); for(int cnt=0;auto it:star){ if(vis[it.x]&&vis[it.y]){ int x=find(it.x),y=find(it.y); if(x==y) continue; fa[x]=y,cnt++,ans+=it.w; if(cnt==tot-1) break; } } cout<<tot<<" "<<ans; return 0; }
|
emm 你谷这道题是蓝…