本题中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;
}

京公网安备 11010502036488号