APIO2015 雅加达的摩天楼
首先可以看出这是一道求最短路的题目,但暴力建图最多n2 条边,所以考虑建图优化
对于p>sqrt(n) 的青蛙可以直接暴力建,最多n*sqrt(n) 条边
对于p<sqrt(n) 的青蛙添加辅助点,枚举这sqrt(n)个长度,每个长度建立n个辅助点前后对应连边,同时向它们可以到达的点以及可以到达它们的点连边
1 #define MAXN 4000010UL 2 #include <cstdio> 3 #include <queue> 4 #include <cmath> 5 #include <cstring> 6 7 using namespace std; 8 9 int n, m, t, inf, S, T, d[MAXN], dis[MAXN], mp[30010][175]; 10 bool ins[MAXN]; 11 12 struct Edge { 13 int hou, nt, zhi; 14 }sg[MAXN<<2]; 15 16 void Add(int x, int y, int z) { 17 sg[t] = (Edge){y, d[x], z}, d[x] = t ++; 18 return; 19 } 20 21 void Spfa(int x) { 22 memset(dis, 0x3f, sizeof(dis)); 23 inf = dis[0]; 24 dis[x] = 0; 25 queue <int> q; q.push(x); 26 while(!q.empty()) { 27 int op = q.front(); q.pop(); 28 ins[op] = false; 29 for(int i = d[op] ; i != -1 ; i = sg[i].nt) if(dis[sg[i].hou]>dis[op]+sg[i].zhi) { 30 dis[sg[i].hou] = dis[op]+sg[i].zhi; 31 if(!ins[sg[i].hou]) { 32 ins[sg[i].hou] = true; 33 q.push(sg[i].hou); 34 } 35 } 36 } 37 return; 38 } 39 40 int main() { 41 memset(d, -1, sizeof(d)); 42 scanf("%d%d", &n, &m); 43 int blo = (int)sqrt(n), tot = n-1; 44 for(int i = 0 ; i < n ; ++ i) { 45 for(int j = 1 ; j <= blo ; ++ j) mp[i][j] = ++ tot, Add(tot, i, 0); 46 } 47 48 for(int i = 0 ; i < n ; ++ i) { 49 for(int j = 1 ; j <= blo ; ++ j) { 50 if(i+j<n) Add(mp[i][j], mp[i+j][j], 1); 51 if(i-j>=0) Add(mp[i][j], mp[i-j][j], 1); 52 } 53 } 54 for(int i = 0, b, p ; i < m ; ++ i) { 55 scanf("%d%d", &b, &p); 56 if(i==0) S = b; 57 if(i==1) T = b; 58 if(p<=blo) Add(b, mp[b][p], 0); 59 else { 60 for(int j = 1 ; b+j*p < n ; ++ j) Add(b, b+j*p, j); 61 for(int j = 1 ; b-j*p >= 0 ; ++ j) Add(b, b-j*p, j); 62 } 63 } 64 Spfa(S); 65 if(dis[T]==inf) printf("-1"); 66 else printf("%d", dis[T]); 67 return 0; 68 }