Question
有1到n个景点,每个景点有一个高度h,从1号节点出发,求能到达多少个景点和最小生成树。
Solution
预处理有向边建图 Kruscal
这道题和普通的求最小生成问题的区别在于,这里是有向路,高度只能从高到低(可以相等)。
那我们需要从1号节点开始dfs预处理能够走得通的有向路,并将走得通的结点数量记录,再用Kruscal去求即可。
不知道是不是哪里写的有问题,没加O(2)+O(3)的情况下超时了,加了就过去了。
感觉应该是我没用不会链式前向星的而用Vector常数太大的缘故吧。
Code
#include<bits/stdc++.h> #pragma GCC optimize(2) #pragma GCC optimize(3) using namespace std; typedef long long ll; typedef pair<int,int>P; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll maxn = 1e6 + 5; const int N = 1e5 + 5; struct edge{int to,cost;}a[N]; vector<edge> G[N]; bool v[N]; ll cnt,tot,ans; int n,m,h[N]; struct node{ int to,from,cost; bool friend operator < (node A,node B) { if (h[A.to]!=h[B.to]) return h[A.to]<h[B.to]; return A.cost>B.cost; } }b; int f[N]; void init(int n){for(int i=0;i<=n;i++) f[i]=i;} inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);} inline void merge(int x,int y){int u=find(x),v=find(y);if(u!=v) f[v]=u;} inline bool check(int x,int y){return find(x)==find(y);} priority_queue<node> q; inline void build(int x){ for(auto c:G[x]){ b.to=c.to,b.cost=c.cost,b.from=x; q.push(b); if(!v[c.to]) v[c.to]=true,build(c.to),cnt++; } } void kruskal(){ init(n); while(!q.empty()&&tot!=cnt){ node t=q.top();q.pop(); int u=find(t.to); int v=find(t.from); if(u!=v){ merge(u,v); ans+=t.cost; tot++; } } } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++){ cin>>h[i]; } for(int i=1;i<=m;i++){ int u,v,w;cin>>u>>v>>w; if(h[u]<h[v]) swap(u,v); G[u].push_back({v,w}); if(h[u]==h[v]) G[v].push_back({u,w}); } v[1]=true;build(1);kruskal(); cout<<cnt+1<<" "<<ans<<'\n'; return 0; }