1. 程式人生 > >洛谷 P2573 [SCOI2012]滑雪

洛谷 P2573 [SCOI2012]滑雪

現在 分層 ans rim 存在 同時 pri pair bfs

題目描述

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 
輸出樣例#1:
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]滑雪