P2573 [SCOI2012]滑雪 题解
下午花了三个小时肝这道题,心态差点爆炸!
下面是分析:
1 题目要求: 2 求最小生成树 3 但是 4 - a是从1号点开始的 --> 如果以后的某个点比一号高,则不可能到达 5 - a只能从高往低处滑 6 - 可能某两个景点没有轨道连接 -->没有处在一个联通快里? 7 8 生成树的要求: 9 - 树根高度最大 10 - 子节点的高度必须比父亲结点小 11 - 边权和尽可能小 12 13 自己造的样例: 14 输入: 15 4 4 16 4 2 3 1 17 1 2 3 18 2 3 2 19 2 4 4 20 3 4 1 21 22 输出: 23 3 7
从题解上爬的Solotion:
1 为保证我们只会由高到低,我们就只建立由高向低的单向边即可。 2 3 对于建立出来的图A,由1点开始宽搜,将扩展到的点和边加入一个新图B, 4 所有扩展到的点便是能到达的最多点。 5 6 我们再在这个新图上跑Kruskal求最小生成树,求得最短距离。 7 8 对于排序部分,为保证有尽可能多的点在最小生成树里, 9 我们按终点的高度为第一关键字从大到小排序,边长为第二关键字从小到大排序; 10 11 这样就能保证拓展的点最多,进而再用最小生成树求最短距离。
最终AC代码:
1 /* 2 Work By:Suzt_ilymtics 3 */ 4 #include<iostream> 5 #include<cstdio> 6 #include<algorithm> 7 #include<queue> 8 using namespace std; 9 const int MAXN=1e5+5; 10 const int MAXM=1e6+6; 11 struct edge{ 12 int from,to,nxt; 13 long long w; 14 }e_a[MAXM << 1],e_b[MAXM << 1]; 15 int head_a[MAXN],num_edge_a; 16 int num_edge_b; 17 int n,m,cnt; 18 long long ans; 19 int h[MAXN],f[MAXN]; 20 bool vis[MAXN]; 21 queue<int> q; 22 23 int find(int x) {return f[x] == x ? x : f[x]=find(f[x]);} 24 25 bool cmp(edge x,edge y){return h[x.to] == h[y.to] ? x.w < y.w : h[x.to] > h[y.to];} 26 27 void add_a(int from,int to,int w){ 28 e_a[++num_edge_a].from = from; 29 e_a[num_edge_a].to = to; 30 e_a[num_edge_a].w = w; 31 e_a[num_edge_a].nxt = head_a[from]; 32 head_a[from] = num_edge_a; 33 } 34 35 void add_b(int from,int to,int w){ 36 e_b[++num_edge_b].from = from; 37 e_b[num_edge_b].to = to; 38 e_b[num_edge_b].w = w; 39 } 40 41 void bfs(int x){ 42 q.push(x);vis[1]=1; 43 while(!q.empty()){ 44 int t=q.front(); q.pop(); 45 for(int i=head_a[t];i;i=e_a[i].nxt){ 46 add_b(e_a[i].from,e_a[i].to,e_a[i].w); 47 if(!vis[e_a[i].to]){ 48 vis[e_a[i].to]=1; 49 q.push(e_a[i].to); 50 cnt++; 51 } 52 } 53 } 54 } 55 56 void kls(){ 57 for(int i=1;i<=num_edge_b;++i){ 58 int uf=find(e_b[i].from),vf=find(e_b[i].to); 59 if( uf == vf ) continue; 60 else{ 61 f[uf] = vf; 62 ans+=e_b[i].w; 63 } 64 } 65 } 66 67 int main() 68 { 69 scanf("%d%d",&n,&m); 70 for(int i=1;i<=n;++i){ 71 scanf("%d",&h[i]),f[i]=i; 72 } 73 for(int i=1,u,v,w;i<=m;++i){ 74 scanf("%d%d%d",&u,&v,&w); 75 if(h[u]>=h[v]) add_a(u,v,w); 76 if(h[u]<=h[v]) add_a(v,u,w); 77 } 78 bfs(1); 79 sort(e_b+1,e_b+num_edge_b+1,cmp); 80 kls(); 81 printf("%d %lld",cnt+1,ans); 82 return 0; 83 }
The end
(这篇文章终于能看了点)