1. 程式人生 > >[SCOI 2012]滑雪與時間膠囊

[SCOI 2012]滑雪與時間膠囊

def namespace 滑雪 blog printf link str sample 不同

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。

題解

對於第一問,我們直接遍歷一遍就好了。

對於第二問,把第一問中的邊取出。結點具有層次性,且不具有環。把邊先按終點高度排序為第一關鍵字(從大到小),邊長為第二關鍵字排序(從大到小)之後,就會保證優先到高點,同高點之間選最小邊。

 1 //It is made by Awson on 2017.10.26
2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <cmath> 7 #include <stack> 8 #include <queue> 9 #include <vector> 10 #include <string> 11 #include <cstdio> 12 #include <cstdlib> 13 #include <cstring> 14 #include <iostream> 15 #include <algorithm> 16 #define LL long long 17 #define link LINK 18 #define Min(a, b) ((a) < (b) ? (a) : (b)) 19 #define Max(a, b) ((a) > (b) ? (a) : (b)) 20 #define Abs(a) ((a) < 0 ? (-(a)) : (a)) 21 using namespace std; 22 const int N = 1e5; 23 const int M = 1e6; 24 25 int n, m, h[N+5], u, v, w, ans1; 26 LL ans2; 27 struct tt { 28 int to, cost, next; 29 }edge[(M<<1)+5]; 30 struct ss { 31 int from, to, cost; 32 bool operator < (const ss &b) const{ 33 return h[to] == h[b.to] ? cost < b.cost : h[to] > h[b.to]; 34 } 35 }link[(M<<1)+5]; 36 int path[N+5], top; 37 bool vis[N+5]; 38 int st[N+5]; 39 40 int find(int r) { 41 return st[r] ? st[r] = find(st[r]) : r; 42 } 43 void bfs() { 44 queue<int>Q; 45 while (!Q.empty()) Q.pop(); 46 Q.push(1); vis[1] = 1; 47 while (!Q.empty()) { 48 int u = Q.front(); ans1++; Q.pop(); 49 for (int i = path[u]; i; i = edge[i].next) 50 if (!vis[edge[i].to]) { 51 Q.push(edge[i].to); vis[edge[i].to] = 1; 52 } 53 } 54 } 55 void add(int u, int v, int c) { 56 edge[++top].to = v; 57 edge[top].cost = c; 58 edge[top].next = path[u]; 59 path[u] = top; 60 } 61 void Kruskal() { 62 int cnt = 0; 63 for (int u = 1; u <= n; u++) 64 for (int j = path[u]; j; j = edge[j].next) 65 if (vis[u] && vis[edge[j].to]) 66 link[++cnt].from = u, link[cnt].to = edge[j].to, link[cnt].cost = edge[j].cost; 67 sort(link+1, link+1+cnt); 68 for (int i = 1; i <= cnt; i++) { 69 int u = link[i].from, v = link[i].to, c = link[i].cost; 70 int p = find(u), q = find(v); 71 if (p != q) { 72 st[p] = q; ans2 += c; 73 } 74 } 75 } 76 void work() { 77 scanf("%d%d", &n, &m); 78 for (int i = 1; i <= n; i++) scanf("%d", &h[i]); 79 for (int i = 1; i <= m; i++) { 80 scanf("%d%d%d", &u, &v, &w); 81 if (h[u] >= h[v]) add(u, v, w); 82 if (h[v] >= h[u]) add(v, u, w); 83 } 84 bfs(); 85 Kruskal(); 86 printf("%d %lld\n", ans1, ans2); 87 } 88 int main() { 89 work(); 90 return 0; 91 }

[SCOI 2012]滑雪與時間膠囊