A - Volleyball

本文介绍了一个结合Dijkstra算法和深度优先搜索(DFS)的比赛路线规划问题解决方案。通过使用邻接表而非矩阵,并优化多条路线间的距离更新,实现了从起点到终点的最短路径寻找。此外,还提供了一种通过生成简化图并应用SPFA算法来进一步优化的方法。
A - Volleyball
Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u
Submit   Status   Practice   CodeForces 96D

Description

Petya loves volleyball very much. One day he was running late for a volleyball match. Petya hasn't bought his own car yet, that's why he had to take a taxi. The city has n junctions, some of which are connected by two-way roads. The length of each road is defined by some positive integer number of meters; the roads can have different lengths.

Initially each junction has exactly one taxi standing there. The taxi driver from the i-th junction agrees to drive Petya (perhaps through several intermediate junctions) to some other junction if the travel distance is not more than ti meters. Also, the cost of the ride doesn't depend on the distance and is equal to ci bourles. Taxis can't stop in the middle of a road. Each taxi can be used no more than once. Petya can catch taxi only in the junction, where it stands initially.

At the moment Petya is located on the junction x and the volleyball stadium is on the junction y. Determine the minimum amount of money Petya will need to drive to the stadium.

Input

The first line contains two integers n and m (1 ≤ n ≤ 1000, 0 ≤ m ≤ 1000). They are the number of junctions and roads in the city correspondingly. The junctions are numbered from 1 to n, inclusive. The next line contains two integers x and y (1 ≤ x, y ≤ n). They are the numbers of the initial and final junctions correspondingly. Next m lines contain the roads' description. Each road is described by a group of three integers ui, vi, wi (1 ≤ ui, vi ≤ n, 1 ≤ wi ≤ 109) — they are the numbers of the junctions connected by the road and the length of the road, correspondingly. The next n lines contain n pairs of integers ti and ci (1 ≤ ti, ci ≤ 109), which describe the taxi driver that waits at the i-th junction — the maximum distance he can drive and the drive's cost. The road can't connect the junction with itself, but between a pair of junctions there can be more than one road. All consecutive numbers in each line are separated by exactly one space character.

Output

If taxis can't drive Petya to the destination point, print "-1" (without the quotes). Otherwise, print the drive's minimum cost.

Please do not use the %lld specificator to read or write 64-bit integers in С++. It is preferred to use cin, cout streams or the %I64d specificator.

Sample Input

Input
4 4
1 3
1 2 3
1 4 1
2 4 1
2 3 5
2 7
7 2
1 2
7 7
Output
9

Hint

An optimal way — ride from the junction 1 to 2 (via junction 4), then from 2 to 3. It costs 7+2=9 bourles.


题目大意:给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\n",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\n",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\n",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\n", 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\n",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\n",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\n",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\n",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\n", G.solve());
138     }
139 }

 


By Oyking

转载于:https://www.cnblogs.com/scnuacm/p/3199968.html

The following is the data that you can add to your input file (as an example). Notice that the first line is going to be a line representing your own hobbies. In my case, it is the Vitaly,table tennis,chess,hacking line. Your goal is to create a class called Student. Every Student will contain a name (String) and an ArrayList<String> storing hobbies. Then, you will add all those students from the file into an ArrayList<Student>, with each Student having a separate name and ArrayList of hobbies. Here is an example file containing students (the first line will always represent yourself). NOTE: eventually, we will have a different file containing all our real names and hobbies so that we could find out with how many people each of us share the same hobby. Vitaly,table tennis,chess,hacking Sean,cooking,guitar,rainbow six Nolan,gym,piano,reading,video games Jack,cooking,swimming,music Ray,piano,video games,volleyball Emily,crochet,drawing,gardening,tuba,violin Hudson,anime,video games,trumpet Matt,piano,Reading,video games,traveling Alex,swimming,video games,saxophone Roman,piano,dancing,art Teddy,chess,lifting,swimming Sarah,baking,reading,singing,theatre Maya,violin,knitting,reading,billiards Amy,art,gaming,guitar,table tennis Daniel,video games,tennis,soccer,biking,trumpet Derek,cooking,flute,gaming,swimming,table tennis Daisey,video games,guitar,cleaning,drawing,animated shows,reading,shopping Lily,flute,ocarina,video games,baking Stella,roller skating,sudoku,watching baseball,harp Sophie,viola,ukulele,piano,video games
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值