本题中a180285的时间胶囊操作其实相当于随意的去走一个树形的结构。那么很容易就想到了最小生成树算法。
但是由于本题中必须从高度高的向高度低的去走。而且图是一个有向图,所以在这里克鲁斯卡尔算法不适用,因为克鲁斯卡尔算法的加边方式不会去在乎单向边的问题。
那么使用prime算法,但是优先队列的条件要稍作改变,由于题目中要求经过景点的数量尽量多为第一优先级。那么就需要首先按照高度进行排序,贪心的去走那个较高的点。
然后才是距离的限制。
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 1e7+10; const int maxm = 1e7+10; struct sy{ int next; int to; int w; } edge[maxm]; int head[maxn]; int cnt = 0; int n, m; int num = 0, cont = 0; int h[maxn], dist[maxn]; bool vis[maxn]; struct Node{ int number; int val; int h; bool operator < (const Node& n) const { if (h==n.h) return val>n.val; else return h<n.h; } }; priority_queue<Node> pq; void add_edge(int u, int v, int w) { edge[++cnt].next = head[u]; edge[cnt].to = v; edge[cnt].w = w; head[u] = cnt; } void init() { memset(dist, 127, sizeof dist); memset(vis, 0, sizeof vis); } void prime(int bg) { pq.push({bg, 0, h[bg]}); dist[bg] = 0; while (pq.size()) { int number = pq.top().number; int temp = pq.top().val; pq.pop(); if (vis[number]) continue; num += temp; vis[number] = true; cont++; for (int i=head[number];~i;i=edge[i].next) { // cout<<"i="<<i<<endl; int next = edge[i].to; int w = edge[i].w; // cout<<"next="<<next<<" w="<<w<<endl; if (vis[next]) continue; if (dist[next]>w) { // dist[next] = w; pq.push({next, w, h[next]}); } } } } signed main() { memset(head, -1, sizeof head); int u, v, w; cin>>n>>m; for (int i=1;i<=n;i++) { cin>>h[i]; } for (int i=1;i<=m;i++) { cin>>u>>v>>w; if (h[u]>=h[v]) add_edge(u, v, w); if (h[u]<=h[v]) add_edge(v, u, w); } //每一个点为起点去求一个有向图的最小生成树,使用prime算法进行计算。 init(); prime(1); cout<<cont<<" "<<num; return 0; }