[SCOI2012]滑雪与时间胶囊
题目描述
a180285非常喜欢滑雪。他来到一座雪山,这里分布着MMM条供滑行的轨道和NNN个轨道之间的交点(同时也是景点),而且每个景点都有一编号iii(1≤i≤N1 \le i \le N1≤i≤N)和一高度HiH_iHi。a180285能从景点iii滑到景点jjj当且仅当存在一条iii和jjj之间的边,且iii的高度不小于jjj。 与其他滑雪爱好者不同,a180285喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。于是a180285拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是a180285 滑行的距离)。请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在111号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入输出格式
输入格式:输入的第一行是两个整数N,MN,MN,M。
接下来111行有NNN个整数HiH_iHi,分别表示每个景点的高度。
接下来MMM行,表示各个景点之间轨道分布的情况。每行333个整数,Ui,Vi,KiU_i,V_i,K_iUi,Vi,Ki。表示编号为UiU_iUi的景点和编号为ViV_iVi的景点之间有一条长度为KiK_iKi的轨道。
输出格式:输出一行,表示a180285最多能到达多少个景点,以及此时最短的滑行距离总和。
输入输出样例
3 3 3 2 1 1 2 1 2 3 1 1 3 10
3 2
说明
【数据范围】
对于30% 30\% 30%的数据,保证 1≤N≤2000 1 \le N \le 2000 1≤N≤2000
对于100% 100\% 100%的数据,保证 1≤N≤105 1 \le N \le 10^5 1≤N≤105
对于所有的数据,保证 $ 1 \le M \le 10^6 , 1 \le H_i \le 10^9,1 \le K_i \le 10^9 $。
按照题目意思就是给你一个有向图,求一个最小树形图,然后如果你用朱刘算法来算,就只能得到70分
因为有神奇的胶囊,所以有向边又可以看成双向边
而且每个选中的景点可以从1用bfs求出数量cnt
可以保证一定有cnt那么多个
这道题的反向边只会在高度相同的点之间出现。如果把边先按终点高度排序为第一关键字,边长为第二关键字排序之后,就会保证优先到高点,同高点之间选小边,然后就不会出现反向的情况,所以可以用kruskal实现用O(mlog(m))的时间复杂度解决这道题。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 typedef long long lol; 8 struct Edge 9 { 10 int u,v; 11 lol w; 12 }e[2000001]; 13 struct Node 14 { 15 int next,to; 16 }edge[2000001]; 17 int set[100001],n,m,num,head[100001],cnt; 18 lol h[100001],ans; 19 bool vis[100001]; 20 void add(int u,int v) 21 { 22 num++; 23 edge[num].next=head[u]; 24 head[u]=num; 25 edge[num].to=v; 26 } 27 int find(int x) 28 { 29 if (set[x]!=x) set[x]=find(set[x]); 30 return set[x]; 31 } 32 bool cmp(Edge a,Edge b) 33 { 34 if (h[a.v]!=h[b.v]) return h[a.v]>h[b.v]; 35 return a.w<b.w; 36 } 37 void bfs() 38 {int i; 39 queue<int> Q; 40 Q.push(1); 41 vis[1]=1; 42 cnt=1; 43 while (Q.empty()==0) 44 { 45 int u=Q.front(); 46 Q.pop(); 47 for (i=head[u];i;i=edge[i].next) 48 { 49 int v=edge[i].to; 50 if (vis[v]==0) 51 {cnt++; 52 Q.push(v); 53 vis[v]=1; 54 } 55 } 56 } 57 cout<<cnt<<' '; 58 } 59 int main() 60 {int i,j; 61 cin>>n>>m; 62 for (i=1;i<=n;i++) 63 scanf("%lld",&h[i]); 64 for (i=1;i<=m;i++) 65 { 66 scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w); 67 if (h[e[i].u]<h[e[i].v]) swap(e[i].u,e[i].v); 68 add(e[i].u,e[i].v); 69 if (h[e[i].u]==h[e[i].v]) add(e[i].v,e[i].u); 70 } 71 bfs(); 72 sort(e+1,e+m+1,cmp); 73 for (i=1;i<=n;i++) 74 set[i]=i; 75 ans=0;j=0; 76 for (i=1;i<=m;i++) 77 { 78 if (vis[e[i].u]==0||vis[e[i].v]==0) continue; 79 int p=find(e[i].u); 80 int q=find(e[i].v); 81 if (p!=q) 82 { 83 set[p]=q; 84 ans+=e[i].w; 85 j++; 86 if (j==cnt-1) break; 87 } 88 } 89 cout<<ans; 90 }