2 3 3 3 1 3 2 1 2 1 2 3 1 1 3 3 3 3 3 1 3 2 1 2 2 2 3 2 1 3 4Sample Output
Case #1: 2 Case #2: 3
这题的难点是层数的处理,有两种处理方法。
一种是仔细想可以想到的,用vector把每层的点存下来,在djkstra松弛操作的同时,对当前点的相邻两层点全部松弛一遍(具体看代码)。
第二种应该是正解,就是拆点。其实上一种也相当于拆点,只不过拆很暴力,不够彻底。
我们可以把层当做一个新的点,在该层的点到该层的距离为0,该层到相邻层的距离为c。但因为同层的点不一定相互联通,所以要把一个层分为两个点,一个入口点,一个出口点,入口点和出口点之间不联通。
法一ac代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 using namespace std; 8 typedef long long ll; 9 const int inf = 0x3f3f3f3f; 10 const int maxn = 1e5 + 10; 11 int n, m, c; 12 int pos[maxn]; 13 vector<int> laye[maxn]; 14 int head[maxn]; 15 int d[maxn]; 16 bool vis[maxn]; 17 bool visi[maxn]; 18 struct edge{ 19 int to, nex, cost; 20 }eg[2 * maxn]; 21 int cnt = 0; 22 inline void add(int u,int v,int cost) { 23 eg[cnt].to = v; 24 eg[cnt].nex = head[u]; 25 eg[cnt].cost = cost; 26 head[u] = cnt++; 27 } 28 struct Rule { 29 bool operator () (int &a,int &b) const { 30 return d[a] > d[b]; 31 } 32 }; 33 inline void dijkstra(int s) { 34 memset(vis, 0, sizeof(vis)); 35 memset(d, inf, sizeof(d)); 36 priority_queue<int, vector<int>, Rule> q; 37 d[s] = 0; 38 q.push(s); 39 while(!q.empty()) { 40 int u = q.top(); q.pop(); 41 for(int k = head[u]; ~k; k = eg[k].nex) { 42 int v = eg[k].to; 43 if(d[v] > d[u] + eg[k].cost) { 44 // printf("%d %d %d\n", u, v,eg[k].cost); 45 d[v] = d[u] + eg[k].cost; 46 q.push(v); 47 } 48 } 49 if(pos[u] < n && !vis[pos[u]+ 1]) { 50 vis[pos[u] + 1] = true; //注意标记层数,不然会超时 51 for(int i = 0; i < laye[pos[u] + 1].size(); ++i) { 52 int v = laye[pos[u] + 1][i]; 53 if(d[v] > d[u] + c) { 54 // printf("%d %d %d\n", u, v,c); 55 d[v] = d[u] + c; 56 q.push(v); 57 58 } 59 } 60 } 61 if(pos[u] > 1 && !vis[pos[u] - 1]) { 62 vis[pos[u] - 1] = true; 63 for(int i = 0; i < laye[pos[u] - 1].size(); ++i) { 64 int v = laye[pos[u] - 1][i]; 65 if(d[v] > d[u] + c) { 66 // printf("%d %d %d\n", u, v,c); 67 d[v] = d[u] + c; 68 q.push(v); 69 70 } 71 } 72 } 73 } 74 } 75 int main() 76 { 77 int t; 78 scanf("%d", &t); 79 for(int cas = 1; cas <= t; ++cas) { 80 cnt = 0; 81 memset(head, -1, sizeof(head)); 82 memset(pos, 0, sizeof(pos)); 83 84 scanf("%d %d %d", &n, &m, &c); 85 int u, v, cost; 86 for(int i = 1; i <= n; ++i) { 87 scanf("%d", &u); 88 pos[i] = u; 89 laye[u].push_back(i); 90 } 91 for(int i =0; i < m; ++i) { 92 scanf("%d %d %d", &u, &v, &cost); 93 add(u, v, cost); 94 add(v, u, cost); 95 } 96 97 dijkstra(1); 98 if(d[n] == inf || n == 0) 99 printf("Case #%d: -1\n", cas); 100 else 101 printf("Case #%d: %d\n", cas, d[n]); 102 for(int i = 1; i <= n; ++i) laye[i].clear(); 103 } 104 return 0; 105 }
法二代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 using namespace std; 8 typedef long long ll; 9 const int inf = 0x3f3f3f3f; 10 const int maxn = 5 * 1e5; 11 int n, m, c; 12 int pos[maxn]; 13 vector<int> laye[maxn]; 14 int head[maxn]; 15 int d[maxn]; 16 bool vis[maxn]; 17 struct edge{ 18 int to, nex, cost; 19 }eg[maxn]; 20 int cnt = 0; 21 void add(int u,int v,int cost) { 22 eg[cnt].to = v; 23 eg[cnt].nex = head[u]; 24 eg[cnt].cost = cost; 25 head[u] = cnt++; 26 } 27 struct Rule { 28 bool operator () (int a,int b) const { 29 return d[a] > d[b]; 30 } 31 }; 32 void dijkstra(int s) { 33 memset(d, inf, sizeof(d)); 34 priority_queue<int, vector<int>, Rule> q; 35 d[s] = 0; 36 q.push(s); 37 while(!q.empty()) { 38 int u = q.top(); q.pop(); 39 for(int k = head[u]; k != -1; k = eg[k].nex) { 40 int v = eg[k].to; 41 if(d[v] > d[u] + eg[k].cost) { 42 // printf("%d %d %d\n", u, v,eg[k].cost); 43 d[v] = d[u] + eg[k].cost; 44 q.push(v); 45 } 46 47 } 48 } 49 } 50 int main() 51 { 52 int t; 53 scanf("%d", &t); 54 for(int cas = 1; cas <= t; ++cas) { 55 56 cnt = 0; 57 memset(d, inf, sizeof(d)); 58 memset(head, -1, sizeof(head)); 59 memset(pos, 0, sizeof(pos)); 60 scanf("%d %d %d", &n, &m, &c); 61 int u, v, cost; 62 for(int i = 1; i <= n; ++i) { 63 scanf("%d", &u); 64 pos[i] = u; 65 add(i, n + 2 * u - 1, 0);//层内的点到该层距离为0 66 add(n + 2 * u, i, 0); 67 vis[u] = true; 68 } 69 for(int i = 1; i < n; ++i) { 70 if(vis[i] && vis[i + 1]) {//这个似乎不加也行 71 add(n + 2 * i - 1, n + 2 * (i + 1), c);//相邻层之间的距离为c 72 add(n + 2 * (i + 1) - 1, n + 2 * i, c); 73 } 74 } 75 for(int i =0; i < m; ++i) { 76 scanf("%d %d %d", &u, &v, &cost); 77 add(u, v, cost); 78 add(v, u, cost); 79 } 80 81 dijkstra(1); 82 if(d[n] == inf || n == 0) 83 printf("Case #%d: -1\n", cas); 84 else 85 printf("Case #%d: %d\n", cas, d[n]); 86 } 87 return 0; 88 }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。