题意:
有n个点,然后有m条边,且你只能从权值高的点走到权值低的点;且你可以回到之前你曾经走过的点,然后问从1出发,最多可以遍历多少个点,且遍历最多点时最小距离是多少?
思路:
首先需要保证遍历的点最多,应该希望新加入的点高度越高越好,因为这样就不会漏掉一些本来可以遍历的点,然后再希望距离越小越好;做一遍prim,将点加入生成树时以高度降序,到生成树距离升序来取,且每到一个点的代价就是这个点到生成树中所有点集中的最短路
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const int N = 1e5+10,M = 2e6+10; struct Edge{ int to,w,nex; }e[M]; int dist[N],H[N]; struct Node{ int high,dist,id; bool operator < (const Node&b) const{ if(high != b.high) return high < b.high; return dist > b.dist; } }; int head[N],idx; void add_edge(int u,int v,int w){ e[idx].to = v; e[idx].w = w; e[idx].nex = head[u]; head[u] = idx++; } void init(){ memset(head,-1,sizeof(head));idx = 0; } int n,m,cnt,intree[N]; ll ans; void prim(){ priority_queue<Node> q; memset(dist,0x3f,sizeof(dist)); dist[1] = 0; q.push((Node){H[1],0,1}); while(q.size()){ int u = q.top().id;q.pop(); if(intree[u]) continue; intree[u] = 1;cnt++,ans+=dist[u]; for(int i = head[u];~i;i = e[i].nex){ int v = e[i].to,w = e[i].w; if(intree[v]) continue; if(dist[v] > w){ dist[v] = w; q.push((Node){H[v],dist[v],v}); } } } } int main(){ scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) scanf("%d",H+i); init(); for(int i = 0,u,v,w;i < m;i++){ scanf("%d%d%d",&u,&v,&w); if(H[u] >= H[v]) add_edge(u,v,w); if(H[v] >= H[u]) add_edge(v,u,w); } prim(); printf("%d %lld\n",cnt,ans); return 0; }