洛谷 P2573 [SCOI2012]滑雪
題目描述
a180285非常喜歡滑雪。他來到一座雪山,這裏分布著M條供滑行的軌道和N個軌道之間的交點(同時也是景點),而且每個景點都有一編號i(1<=i<=N)和一高度Hi。a180285能從景點i 滑到景點j 當且僅當存在一條i 和j 之間的邊,且i 的高度不小於j。 與其他滑雪愛好者不同,a180285喜歡用最短的滑行路徑去訪問盡量多的景點。如果僅僅訪問一條路徑上的景點,他會覺得數量太少。於是a180285拿出了他隨身攜帶的時間膠囊。這是一種很神奇的藥物,吃下之後可以立即回到上個經過的景點(不用移動也不被認為是a180285 滑行的距離)。請註意,這種神奇的藥物是可以連續食用的,即能夠回到較長時間之前到過的景點(比如上上個經過的景點和上上上個經過的景點)。 現在,a180285站在1號景點望著山下的目標,心潮澎湃。他十分想知道在不考慮時間
膠囊消耗的情況下,以最短滑行距離滑到盡量多的景點的方案(即滿足經過景點數最大的前提下使得滑行總距離最小)。你能幫他求出最短距離和景點數嗎?
輸入輸出格式
輸入格式:
輸入的第一行是兩個整數N,M。
接下來1行有N個整數Hi,分別表示每個景點的高度。
接下來M行,表示各個景點之間軌道分布的情況。每行3個整數,Ui,Vi,Ki。表示
編號為Ui的景點和編號為Vi的景點之間有一條長度為Ki的軌道。
輸出格式:
輸出一行,表示a180285最多能到達多少個景點,以及此時最短的滑行距離總和。
輸入輸出樣例
輸入樣例#1:3 3 3 2 1 1 2 1 2 3 1 1 3 10
3 2
說明
【數據範圍】
對於30%的數據,保證 1<=N<=2000
對於100%的數據,保證 1<=N<=100000
對於所有的數據,保證 1<=M<=1000000,1<=Hi<=1000000000,1<=Ki<=1000000000。
這題目的題意真是看不懂
大概意思是給出一張有向圖,邊的方向是從高到低,讓你求一個最小樹形圖
朱劉算法怒艹1e13也不是不可以啊
這道題的思路確實很妙,沒看題解想不到
首先觀察發現能到達的點就是一遍BFS,這些點肯定都要到達
然後走過的路徑是一個以1為根的最小樹形圖
直接朱劉算法肯定不行,需要考慮別的辦法
這張圖的的性質是邊只從高連向低,同高度之間是無向邊
如果把點按照高度分層,那麽有向邊只從高的一層連向低的一層,層內只有無向邊
這有什麽用呢?
我們知道,對於無向圖的樹形圖(即生成樹),有很優秀的辦法來解決,為什麽kruskal和prim不能做有向圖的樹形圖呢?稍微嘗試幾個例子以後會發現,如果用無向圖的方法來做,會有兩個問題
1、答案不是最優,這是由於prim的加入順序問題導致的
2、做出來的根本不是樹形圖,kruskal沒法處理這種情況
但是對於DAG這種特殊的圖而言,無向圖的方法加上一些魔改就可以做了,對於kruskal而言,把邊按照終點的拓撲序為第一關鍵字,邊長為第二關鍵字排序,然後往裏加就行了
讓我們回到這道題的圖,我們發現這張圖很像是一層層的DAG加上層內的無向圖,是不是胡搞一下就好了啊?
發現是的,一樣這麽做就行,第一關鍵字h降序,第二關鍵字變長升序,原因是這樣既不會產生第一個問題(按順序一層層加入,答案不會變劣),也不會產生第二個問題(層間不會有問題,層內是無向邊,可以隨意分配)
然後跑kruskal即可
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <algorithm> 5 #include <string> 6 #include <cstring> 7 #include <cmath> 8 #include <map> 9 #include <stack> 10 #include <set> 11 #include <vector> 12 #include <queue> 13 #include <time.h> 14 #include <functional> 15 #define eps 1e-7 16 #define INF 0x3f3f3f3f 17 #define MOD 1000000007 18 #define rep0(j,n) for(int j=0;j<n;++j) 19 #define rep1(j,n) for(int j=1;j<=n;++j) 20 #define pb push_back 21 #define set0(n) memset(n,0,sizeof(n)) 22 #define ll long long 23 #define ull unsigned long long 24 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt) 25 #define max(a,b) (a>b?a:b) 26 #define min(a,b) (a<b?a:b) 27 #define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0) 28 #define TO(j) printf(#j": %d\n",j); 29 //#define OJ 30 using namespace std; 31 const int MAXINT = 100010; 32 const int MAXNODE = 100010; 33 const int MAXEDGE = 4 * 1000010; 34 char BUF, *buf; 35 int read() { 36 char c = getchar(); int f = 1, x = 0; 37 while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();} 38 while (isdigit(c)) {x = x * 10 + c - ‘0‘; c = getchar();} 39 return f * x; 40 } 41 char get_ch() { 42 char c = getchar(); 43 while (!isalpha(c)) c = getchar(); 44 return c; 45 } 46 //------------------- Head Files ----------------------// 47 int cnt, n, m; 48 int vis[MAXNODE],ans,h[MAXNODE],qu[MAXNODE],fa[MAXNODE]; 49 struct edge { 50 int u, v, l; 51 edge *nxt; 52 edge(int _u, int _v, int _l, edge * _nxt): u(_u), v(_v), l(_l), nxt(_nxt) {} 53 edge() {} 54 } mp[MAXEDGE], *head[MAXNODE]; 55 bool operator < (const edge &a,const edge &b){ 56 return h[a.v]==h[b.v]?a.l<b.l:h[a.v]>h[b.v]; 57 } 58 void get_input(); 59 void work(); 60 void addedge(int u, int v,int l) { 61 mp[cnt] = edge(u, v, l,head[u]); 62 head[u] = &mp[cnt++]; 63 } 64 /*void spfa(int ss, int tt) { 65 memset(dis, 0x3f, sizeof(dis)); 66 dis[ss] = 0; 67 int *h, *t; 68 h = t = q; 69 *t++ = ss; 70 while (h != t) { 71 int p = *h++; inq[p] = 0; 72 iter(i, p) { 73 if (dis[i->v] > dis[p] + i->l) { 74 dis[i->v] = dis[p] + i->l; 75 if (!inq[i->v]) { 76 *t++ = i->v; 77 inq[i->v] = 1; 78 } 79 } 80 } 81 } 82 }*/ 83 /*void dijkstra(int ss,int tt){ 84 memset(dis,0x3f,sizeof(dis)); 85 dis[ss]=0; 86 q.push(make_pair(0,ss)); 87 int T=n-1; 88 while(T--){ 89 while(!q.empty()&&vis[q.top().second]) q.pop(); 90 if(q.empty()) break; 91 int p = q.top().second;q.pop(); 92 iter(i,p){ 93 if(dis[i->v]>dis[p]+i->l){ 94 dis[i->v]=dis[p]+i->l; 95 q.push(make_pair(dis[i->v],i->v)); 96 } 97 } 98 } 99 }*/ 100 void bfs(int p){ 101 int *h,*t; 102 h=t=qu; 103 vis[1]=1;ans=1; 104 *t++=1; 105 while(h!=t){ 106 int p=*h++; 107 iter(i,p){ 108 if(!vis[i->v]) {vis[i->v]=1;ans++;*t++=i->v;} 109 } 110 } 111 } 112 int findfa(int p) {return p==fa[p]?p:fa[p]=findfa(fa[p]);} 113 int main() { 114 get_input(); 115 work(); 116 return 0; 117 } 118 void work() { 119 //dijkstra(1,n); 120 bfs(1); 121 rep1(i,n) fa[i]=i; 122 sort(mp,mp+cnt); 123 ull sum=0; 124 rep0(i,cnt){ 125 int u=mp[i].u,v=mp[i].v; 126 if(!vis[u]||!vis[v]) continue; 127 u=findfa(u);v=findfa(v); 128 if(u!=v) {fa[u]=v; sum+=mp[i].l;} 129 } 130 printf("%d %llu\n",ans,sum); 131 } 132 void get_input() { 133 n = read(); m = read(); 134 rep1(i, n) h[i] = read(); 135 rep0(i, m) { 136 int u = read(), v = read(), l = read(); 137 if (h[u] > h[v]) addedge(u, v, l); 138 if (h[u] == h[v]) {addedge(u, v, l); addedge(v, u, l);} 139 if (h[u] < h[v]) addedge(v, u, l); 140 } 141 142 }
洛谷 P2573 [SCOI2012]滑雪