题目大意:给n个点,m条双向边,每条路均有一个距离,从一个点x出发,最多能花费c[x]走距离t[x]的路,求从起点到终点的最小花费。
官方题解1:
Some of the things which I did not take note of during the competition which prevented my solution from passing. Use adjacency list instead of matrix as the number of roads are only 1000. The question says that there can be multiple roads between junctions so updation needs to be done to adj[s][e] when a lower distance comes up.
Approach
A combination of djikstra and DFS allows us to find the minimum cost incurred in traversing the points. Update your djikstra cost array at all nodes which can be visited from the taxi you are in. This can be done using DFS. Again find the minimum cost junction and continue. If at the end you are not able to reach the destination output should be -1.
官方题解2:
At first in this simple problem you need to find shortest path between all pair of junctions. That can’t be done using O(N^3) algorithms, so you must use Dijkstra algorithm to find this in O(N*N*logN) time. Next part of this problem is to create new matrix, G[i][j] = C[i], if D[i][j] <= R[i], else G[i][j] = INF. Here D[i][j] – length of shortest path between I and j. So, result is shortest path between X and Y using matrix G. That can be done using simple Dijkstra algorithm.
思路:
这题看完题目就会做了,得益于之前做过某题:http://www.cnblogs.com/oyking/archive/2013/06/04/3116617.html,大题思路为,暴搜每个点走距离t[x]能到达的点,为每对这样的点之间连一条边,权值为c[x],然后在后来得到的图上直接求最短路径(最普通的SPFA算法)即可。
另,一开始若暴搜没有剪枝,我曾试过把最短路径图上的边都输出来,发现一个小图却会有很多边,果断优化。之后想挫了以为搜索的时候 每个点经过一次就可以了,后来发现这样不对,因为有可能第一次经过点y的时候,还可以走距离A,第二次经过点y的时候,还可以做距离B,完全有可能是 A<B。基于这个想法,类似可以把A记录下来,若A<B才继续搜索,否则剪枝。
不剪枝的话生成的边太多了,会爆(AC之后手贱交了一次,因为眼挫以为自己WA了)
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 typedef long long LL; 7 8 const int MAXN = 1010; 9 const int MAXM = 5000010; 10 int n, m, x, y; 11 12 void tle() { 13 while(1) ; 14 } 15 16 struct Shortest_path { 17 int head[MAXN], inque[MAXN]; 18 int next[MAXM], to[MAXM], cost[MAXM]; 19 int ecnt, st, ed; 20 LL dis[MAXN]; 21 22 void SPFA() { 23 queue<int> Q; 24 Q.push(st); 25 memset(inque, 0, sizeof(inque)); 26 memset(dis, 255, sizeof(dis)); 27 dis[st] = 0; 28 while(!Q.empty()) { 29 int u = Q.front(); Q.pop(); 30 inque[u] = false; 31 for(int p = head[u]; p; p = next[p]) { 32 int v = to[p]; 33 if(dis[v] < 0 || dis[v] > dis[u] + cost[p]) { 34 dis[v] = dis[u] + cost[p]; 35 //printf("%d %I64d ",v,dis[v]); 36 if(!inque[v]) { 37 inque[v] = true; 38 Q.push(v); 39 } 40 } 41 } 42 } 43 } 44 45 void addEdge(int u, int v, int c) { 46 to[ecnt] = v; cost[ecnt] = c; 47 next[ecnt] = head[u]; head[u] = ecnt++; 48 //printf("%d->%d %d ",u,v,c); 49 //if(ecnt == MAXM) tle(); 50 } 51 52 void init(int ss, int tt) { 53 st = ss; ed = tt; 54 ecnt = 2; 55 memset(head, 0, sizeof(head)); 56 } 57 58 LL solve() { 59 SPFA(); 60 return dis[ed]; 61 } 62 } G; 63 64 const int M = MAXN * 2; 65 66 struct Tree { 67 int head[MAXN], c[MAXN], t[MAXN]; 68 int small[MAXN]; 69 int next[M], to[M], cost[M]; 70 int ecnt; 71 72 void dfs(int root, int u, int rest) { 73 for(int p = head[u]; p; p = next[p]) { 74 int v = to[p]; 75 if(rest - cost[p] < small[v]) continue; 76 if(rest - cost[p] >= 0) { 77 G.addEdge(root, v, c[root]); 78 small[v] = rest - cost[p]; 79 if(rest) dfs(root, v, rest - cost[p]); 80 } 81 } 82 } 83 84 void addEdge(int u, int v, int cc) { 85 to[ecnt] = v; cost[ecnt] = cc; 86 next[ecnt] = head[u]; head[u] = ecnt++; 87 //printf("%d->%d %d ",u,v,cc); 88 } 89 90 void init() { 91 ecnt = 2; 92 memset(head, 0, sizeof(head)); 93 } 94 95 void make_G() { 96 for(int i = 1; i <= n; ++i) { 97 memset(small, 0, sizeof(small)); 98 small[i] = 0x7fffffff; 99 dfs(i, i, t[i]); 100 } 101 } 102 } T; 103 104 int main() { 105 while(scanf("%d%d", &n, &m) != EOF) { 106 scanf("%d%d", &x, &y); 107 G.init(x, y); 108 T.init(); 109 int u, v, c; 110 for(int i = 0; i < m; ++i) { 111 scanf("%d%d", &u, &v); 112 scanf("%d", &c); 113 T.addEdge(u, v, c); 114 T.addEdge(v, u, c); 115 } 116 for(int i = 1; i <= n; ++i) { 117 scanf("%d", &T.t[i]); 118 scanf("%d", &T.c[i]); 119 } 120 T.make_G(); 121 printf("%I64d ", G.solve()); 122 } 123 }
献上真·AC代码,这个应该没问题了,理论上来说上面的那个代码可以卡(可以卡边数卡爆),实际上可以直接用SPFA求第一张图的最短路然后再判断某点x是否能到底某点y,SPFA在稀疏图上常数灰常小,在这提上是灰常适用的。
PS:下面的两个类实际上可以合在一起,但是我懒得搞了就这样吧……
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 6 typedef long long LL; 7 8 const int MAXN = 1010; 9 const int MAXM = 1000010; 10 int n, m, x, y; 11 12 void tle() { 13 while(1) ; 14 } 15 16 struct Shortest_path { 17 int head[MAXN], inque[MAXN]; 18 int next[MAXM], to[MAXM], cost[MAXM]; 19 int ecnt, st, ed; 20 LL dis[MAXN]; 21 22 void SPFA() { 23 queue<int> Q; 24 Q.push(st); 25 memset(inque, 0, sizeof(inque)); 26 memset(dis, 255, sizeof(dis)); 27 dis[st] = 0; 28 while(!Q.empty()) { 29 int u = Q.front(); Q.pop(); 30 inque[u] = false; 31 for(int p = head[u]; p; p = next[p]) { 32 int v = to[p]; 33 if(dis[v] < 0 || dis[v] > dis[u] + cost[p]) { 34 dis[v] = dis[u] + cost[p]; 35 //printf("%d %I64d ",v,dis[v]); 36 if(!inque[v]) { 37 inque[v] = true; 38 Q.push(v); 39 } 40 } 41 } 42 } 43 } 44 45 void addEdge(int u, int v, int c) { 46 to[ecnt] = v; cost[ecnt] = c; 47 next[ecnt] = head[u]; head[u] = ecnt++; 48 //printf("%d->%d %d ",u,v,c); 49 //if(ecnt == MAXM) tle(); 50 } 51 52 void init(int ss, int tt) { 53 st = ss; ed = tt; 54 ecnt = 2; 55 memset(head, 0, sizeof(head)); 56 } 57 58 LL solve() { 59 SPFA(); 60 return dis[ed]; 61 } 62 } G; 63 64 const int M = MAXN * 2; 65 66 struct Tree { 67 int head[MAXN], inque[MAXN], c[MAXN], t[MAXN]; 68 int next[M], to[M], cost[M]; 69 int ecnt; 70 LL dis[MAXN]; 71 72 void SPFA(int st) { 73 queue<int> Q; 74 Q.push(st); 75 memset(inque, 0, sizeof(inque)); 76 memset(dis, 255, sizeof(dis)); 77 dis[st] = 0; 78 while(!Q.empty()) { 79 int u = Q.front(); Q.pop(); 80 inque[u] = false; 81 for(int p = head[u]; p; p = next[p]) { 82 int v = to[p]; 83 if(dis[v] < 0 || dis[v] > dis[u] + cost[p]) { 84 dis[v] = dis[u] + cost[p]; 85 //printf("%d %I64d ",v,dis[v]); 86 if(!inque[v]) { 87 inque[v] = true; 88 Q.push(v); 89 } 90 } 91 } 92 } 93 } 94 95 void addEdge(int u, int v, int cc) { 96 to[ecnt] = v; cost[ecnt] = cc; 97 next[ecnt] = head[u]; head[u] = ecnt++; 98 //printf("%d->%d %d ",u,v,cc); 99 } 100 101 void init() { 102 ecnt = 2; 103 memset(head, 0, sizeof(head)); 104 } 105 106 void make_G() { 107 for(int i = 1; i <= n; ++i) { 108 SPFA(i); 109 for(int j = 1; j <= n; ++j) { 110 if(i == j) continue; 111 if(dis[j] >= 0 && dis[j] <= t[i]) { 112 G.addEdge(i, j, c[i]); 113 } 114 } 115 } 116 } 117 } T; 118 119 int main() { 120 int i; 121 while(scanf("%d%d", &n, &m) != EOF) { 122 scanf("%d%d", &x, &y); 123 G.init(x, y); 124 T.init(); 125 int u, v, c; 126 for(i = 0; i < m; ++i) { 127 scanf("%d%d", &u, &v); 128 scanf("%d", &c); 129 T.addEdge(u, v, c); 130 T.addEdge(v, u, c); 131 } 132 for(i = 1; i <= n; ++i) { 133 scanf("%d", &T.t[i]); 134 scanf("%d", &T.c[i]); 135 } 136 T.make_G(); 137 printf("%I64d ", G.solve()); 138 } 139 }
By Oyking