题意:
有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;
}
京公网安备 11010502036488号