分析
本题的要点在于i到j有通路必须所有我们可以根据给出的建图。
那么第一个问题就是求从1出发,最多可以经过多少个点,这个问题用BFS/DFS
统计下点的个数即可。
主要问题在于第二个问题,因为题目说不考虑时间胶囊的消耗,而且可以连续食用,所以最后走出来的形状一定是树的样子。但是由于路线方向是根据的高度所决定的,只能从高处到低处,所以并不是最小生成树。
但是本题可以理解为一个最小生成树的变型问题,在本题中若从点u到点v,必须满足如下的要求:
- u和v都和起点连通
那我们可以根据算法的思想,定义以下的排序原则:
- 若,则按照来排序
- 否则按照高度排序
这样相当于我们在一层一层扩展,先把最高层的点加入最小树形图然后次高层依次类推,这样所有的边就是按照从高的低的方向走的了。
Tags
- 最小生成树
- 树论
参考代码
//#include <bits/stdc++.h> #include <iostream> #include <iomanip> #include <bitset> #include <string> #include <set> #include <stack> #include <sstream> #include <list> //#include <array> #include <vector> #include <queue> #include <map> #include <memory> #include <iterator> #include <climits> #include <cassert> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define FAST_IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define all(x) (x).begin(), (x).end() typedef long long ll; typedef unsigned int UINT; typedef unsigned long long ull; typedef pair<int, int> pdi; typedef pair<ll, int> pli; int const maxn = 1e5 + 10; const int INF = 0x3f3f3f3f; const ll INFL = 0x3f3f3f3f3f3f3f3f; inline int lc(int x) {return x << 1;} inline int rc(int x) {return x << 1 | 1;} int n, m; ll h[maxn], fa[maxn]; vector<int> e[maxn]; struct Edge { int u, v; ll w; Edge(const int &u = 0, const int &v = 0, const ll&w = 0) : u(u), v(v), w(w) { } bool operator<(const Edge & E) const { if (h[v] == h[E.v]) return w < E.w; return h[v] > h[E.v]; } }; vector<Edge> a; void init() { for (int i = 1; i <= n; i++) { fa[i] = i; } } int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int vis[maxn]; ll bfs(int x) { ll ans = 0; queue<int> q; q.push(1); while (!q.empty()) { int u = q.front(); q.pop(); if (vis[u]) continue; vis[u] = 1; ans++; for (auto &x : e[u]) { q.push(x); } } return ans; } ll kruskal() { ll ans = 0; sort(a.begin(), a.end()); for (auto & x : a) { int u = x.u, v = x.v; ll w = x.w; if (!vis[u] || !vis[v]) continue; int fx = find(u); int fy = find(v); if (fx != fy) { fa[fx] = fy; ans += w; } } return ans; } int main(void) { FAST_IO; cin >> n >> m; init(); for (int i = 1; i <= n; i++) { cin >> h[i]; } for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; if (h[v] >= h[u]) { e[v].push_back(u); a.emplace_back(v, u, w); } if (h[u] >= h[v]) { e[u].push_back(v); a.emplace_back(u, v, w); } } ll ans1 = bfs(1); ll ans2 = kruskal(); cout << ans1 << " " << ans2 << endl; return 0; }