算法题(237):滑雪
审题:
本题需要我们找到从1号景点开始滑雪所能经过的最多景点数,以及经过最多景点时最小的滑雪路径和思路:
方法一:dfs+kruskal算法题意:
1.起点是1号节点
2.一共有n个节点,m条边
3.滑雪时只能从高处往下滑或者平着滑
4.由于有时间胶囊,所以可以无代价回溯节点
目标:
1.找到能经过的最多景点数
2.经过最多景点时最小的滑雪路径和
dfs深度优先遍历
由于可以无条件回溯节点,所以我们可以使用dfs遍历寻找到所有从1号节点出发能到达的节点,从而解决目标1
kruskal算法
目标2的意思是让我们找到"最小生成树",从而将最小路径和求出。本题不是真正意义上的最小生成树,因为滑雪方向有限制,有些方向是不能通过的,不是无向图
解题:
(1)数据初始化#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1e5 + 10, M = 2e6 + 10; int n, m; ll cnt, ret,pos; int f[N],h[N]; bool st[N]; vector<pii> edges[M];//用于存储初始图 struct edge//用于存储纳入考虑的边 {int x, y, z; }e[M];
关键1:要存储初始图以及kruskal算法使用的图
由于给定的图不一定是连通图,所以不是所有的边都要纳入kruskal算法的考量的,那么我们就需要先存储初始图,然后在dfs中再将从1号节点出发可以经过的边存储起来并提供给kruskal计算
(2)main函数
int main() {cin >> n >> m;for (int i = 1; i <= n; i++) cin >> h[i];for (int i = 1; i <= m; i++){int a, b, c; cin >> a >> b >> c;//按照高度判断是否可以建立边if (h[a] >= h[b]) edges[a].push_back({ b,c });if (h[a] <= h[b]) edges[b].push_back({ a,c });}dfs(1);cout << cnt << " ";kruskal();cout << ret << endl;return 0; }
关键2:初始图边的记录
1.a高于b:存储a->b的边
2.a等于b:存储a->b的边,b->a的边
3.b高于a:存储b->a的边
所以我们用两个if语句进行判断,并进行图的存储
(3)dfs
//dfs查找从1号节点可以到达的所有边,并求出最多可到达的节点数 void dfs(int num) {cnt++;st[num] = true;for (auto& f : edges[num]){pos++;e[pos].x = num, e[pos].y = f.first, e[pos].z = f.second;if (!st[f.first]) dfs(f.first);} }
每次进入dfs就相当于进入了一个新的节点,负责记录节点数的cnt++,并修改节点状态
然后对该节点的所有能去的地方进行遍历,这些边就是kruskal需要纳入考虑的
然后如果此时遍历的节点也是没有到过,dfs该节点
(4)kruskal算法
//排序逻辑函数 bool cmp(edge& a, edge& b) {int y1 = a.y, z1 = a.z, y2 = b.y, z2 = b.z;if (h[y1] != h[y2]){return h[y1] > h[y2];}else{return z1 < z2;} } //并查集find函数 int find(int num) {return f[num] == num ? num : f[num] = find(f[num]); } //kruskal void kruskal() {//并查集初始化for (int i = 1; i <= n; i++){f[i] = i;}//排序sort(e + 1, e + 1 + pos, cmp);for (int i = 1; i <= pos; i++){int x = e[i].x, y = e[i].y, z = e[i].z;int fx = find(x), fy = find(y);if (fx != fy){ret += z;f[fx] = fy;}} }
关键3:排序逻辑
由于这里不是无向图,我们如果先滑到低点,就无法从低点滑到高点了,从而导致经过的点变少,故我们需要尽量先滑到较高点,若目标点高度一致,则让路径权值小的排前面
P2573 [SCOI2012] 滑雪 - 洛谷