1. 程式人生 > >2753: [SCOI2012]滑雪與時間膠囊

2753: [SCOI2012]滑雪與時間膠囊

ace sum space sub ans 生成 需要 分層 long

2753: [SCOI2012]滑雪與時間膠囊

Time Limit: 50 Sec Memory Limit: 128 MB
Submit: 2633 Solved: 910

Description

a180285非常喜歡滑雪。他來到一座雪山,這裏分布著M條供滑行的軌道和N個軌道之間的交點(同時也是景點),而且每個景點都有一編號i(1<=i<=N)和一高度Hi。a180285能從景點i 滑到景點j 當且僅當存在一條i 和j 之間的邊,且i 的高度不小於j。 與其他滑雪愛好者不同,a180285喜歡用最短的滑行路徑去訪問盡量多的景點。如果僅僅訪問一條路徑上的景點,他會覺得數量太少。於是a180285拿出了他隨身攜帶的時間膠囊。這是一種很神奇的藥物,吃下之後可以立即回到上個經過的景點(不用移動也不被認為是a180285 滑行的距離)。請註意,這種神奇的藥物是可以連續食用的,即能夠回到較長時間之前到過的景點(比如上上個經過的景點和上上上個經過的景點)。 現在,a180285站在1號景點望著山下的目標,心潮澎湃。他十分想知道在不考慮時間 膠囊消耗的情況下,以最短滑行距離滑到盡量多的景點的方案(即滿足經過景點數最大的前提下使得滑行總距離最小)。你能幫他求出最短距離和景點數嗎?

Input

輸入的第一行是兩個整數N,M。 接下來1行有N個整數Hi,分別表示每個景點的高度。 接下來M行,表示各個景點之間軌道分布的情況。每行3個整數,Ui,Vi,Ki。表示 編號為Ui的景點和編號為Vi的景點之間有一條長度為Ki的軌道。

Output

輸出一行,表示a180285最多能到達多少個景點,以及此時最短的滑行距離總和。

Sample Input


3 3
3 2 1
1 2 1
2 3 1
1 3 10

Sample Output

3 2

HINT

【數據範圍】

對於30%的數據,保證 1<=N<=2000


對於100%的數據,保證 1<=N<=100000

對於所有的數據,保證 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。

分成兩問,首先找出能到達的點(bfs),在算距離(kruskal),最小生成樹時可以按高度為第一關鍵字,權值為第二關鍵字排序。先處理高的點,在處理低的點。

排序之後,我們首先拿到的是高度較高,權值較小的邊,然後判斷能不能到達這兩個點(在搜索時處理),之後依次放高度較低的邊(層層往下,知道最底層,什麽也到不了)。高度相等的點不需要在考慮高度的影響,直接找最小的邊,所以我們開始時先按高度在按權值排序,即分層最小生成樹。

 1
#include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 5 using namespace std; 6 const int MAXN = 100010; 7 const int MAXM = 2000100; 8 struct Edge{ 9 int x,y; 10 long long w; 11 }e[MAXM]; 12 struct Node{ 13 int nxt,to; 14 }t[MAXM]; 15 int head[MAXN],h[MAXN],fa[MAXN]; 16 bool vis[MAXN]; 17 int n,m,cnt,ans=1; 18 long long sum; 19 queue<int>q; 20 21 void add(int u,int v,long long w) 22 { 23 ++cnt; 24 t[cnt].to = v; 25 t[cnt].nxt = head[u]; 26 head[u] = cnt; 27 e[cnt] = (Edge){u,v,w}; 28 } 29 int find(int x) 30 { 31 return x==fa[x]?x:fa[x]=find(fa[x]); 32 } 33 bool cmp(Edge a,Edge b) //先按高度排序,再按權值 34 { 35 return h[a.y]>h[b.y] || (h[a.y]==h[b.y] && a.w<b.w); 36 } 37 void bfs() //搜索出能夠到達的點,和點的個數 38 { 39 q.push(1); 40 vis[1] = true; 41 while (!q.empty()) 42 { 43 int u = q.front(); 44 q.pop(); 45 for (int i=head[u]; i; i=t[i].nxt) 46 { 47 int v = t[i].to; 48 if (!vis[v]) 49 { 50 q.push(v); 51 vis[v] = true; 52 ans++; 53 } 54 } 55 } 56 printf("%d",ans); 57 } 58 void init() 59 { 60 scanf("%d%d",&n,&m); 61 for (int i=1; i<=n; ++i) 62 { 63 scanf("%d",&h[i]); 64 fa[i] = i; //初始化 65 } 66 for (int x,y,i=1; i<=m; ++i) 67 { 68 long long z; 69 scanf("%d%d%lld",&x,&y,&z); 70 if (h[x]>=h[y]) add(x,y,z); //排序時,結構體中是小的 71 if (h[y]>=h[x]) add(y,x,z); 72 } 73 } 74 void work() 75 { 76 sort(e+1,e+cnt+1,cmp); 77 for (int i=1; i<=cnt; ++i) 78 { 79 if (!vis[e[i].x] || !vis[e[i].y]) continue ; //不能到達,就continue 80 int rx = find(e[i].x); 81 int ry = find(e[i].y); 82 if (rx!=ry) 83 { 84 fa[rx] = ry; 85 sum += e[i].w; 86 } 87 } 88 printf(" %lld",sum); 89 } 90 int main() 91 { 92 init(); //初始化,輸入 93 bfs(); //bfs求能到達的點 94 work(); //kruskal求距離 95 return 0; 96 }

2753: [SCOI2012]滑雪與時間膠囊