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 uiviwi (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.

题目大意:给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了)
PS:这代码AC过一次之后就没AC过了,这是什么现象我至今没搞懂……
 
 #include <cstdio>
#include <cstring>
#include <queue>
using namespace std; typedef long long LL; const int MAXN = ;
const int MAXM = ;
int n, m, x, y; void tle() {
while() ;
} struct Shortest_path {
int head[MAXN], inque[MAXN];
int next[MAXM], to[MAXM], cost[MAXM];
int ecnt, st, ed;
LL dis[MAXN]; void SPFA() {
queue<int> Q;
Q.push(st);
memset(inque, , sizeof(inque));
memset(dis, , sizeof(dis));
dis[st] = ;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inque[u] = false;
for(int p = head[u]; p; p = next[p]) {
int v = to[p];
if(dis[v] < || dis[v] > dis[u] + cost[p]) {
dis[v] = dis[u] + cost[p];
//printf("%d %I64d\n",v,dis[v]);
if(!inque[v]) {
inque[v] = true;
Q.push(v);
}
}
}
}
} void addEdge(int u, int v, int c) {
to[ecnt] = v; cost[ecnt] = c;
next[ecnt] = head[u]; head[u] = ecnt++;
//printf("%d->%d %d\n",u,v,c);
//if(ecnt == MAXM) tle();
} void init(int ss, int tt) {
st = ss; ed = tt;
ecnt = ;
memset(head, , sizeof(head));
} LL solve() {
SPFA();
return dis[ed];
}
} G; const int M = MAXN * ; struct Tree {
int head[MAXN], c[MAXN], t[MAXN];
int small[MAXN];
int next[M], to[M], cost[M];
int ecnt; void dfs(int root, int u, int rest) {
for(int p = head[u]; p; p = next[p]) {
int v = to[p];
if(rest - cost[p] < small[v]) continue;
if(rest - cost[p] >= ) {
G.addEdge(root, v, c[root]);
small[v] = rest - cost[p];
if(rest) dfs(root, v, rest - cost[p]);
}
}
} void addEdge(int u, int v, int cc) {
to[ecnt] = v; cost[ecnt] = cc;
next[ecnt] = head[u]; head[u] = ecnt++;
//printf("%d->%d %d\n",u,v,cc);
} void init() {
ecnt = ;
memset(head, , sizeof(head));
} void make_G() {
for(int i = ; i <= n; ++i) {
memset(small, , sizeof(small));
small[i] = 0x7fffffff;
dfs(i, i, t[i]);
}
}
} T; int main() {
while(scanf("%d%d", &n, &m) != EOF) {
scanf("%d%d", &x, &y);
G.init(x, y);
T.init();
int u, v, c;
for(int i = ; i < m; ++i) {
scanf("%d%d", &u, &v);
scanf("%d", &c);
T.addEdge(u, v, c);
T.addEdge(v, u, c);
}
for(int i = ; i <= n; ++i) {
scanf("%d", &T.t[i]);
scanf("%d", &T.c[i]);
}
T.make_G();
printf("%I64d\n", G.solve());
}
}

献上真·AC代码,这个应该没问题了,理论上来说上面的那个代码可以卡(可以卡边数卡爆),实际上可以直接用SPFA求第一张图的最短路然后再判断某点x是否能到底某点y,SPFA在稀疏图上常数灰常小,在这提上是灰常适用的。

PS:下面的两个类实际上可以合在一起,但是我懒得搞了就这样吧……

 #include <cstdio>
#include <cstring>
#include <queue>
using namespace std; typedef long long LL; const int MAXN = ;
const int MAXM = ;
int n, m, x, y; void tle() {
while() ;
} struct Shortest_path {
int head[MAXN], inque[MAXN];
int next[MAXM], to[MAXM], cost[MAXM];
int ecnt, st, ed;
LL dis[MAXN]; void SPFA() {
queue<int> Q;
Q.push(st);
memset(inque, , sizeof(inque));
memset(dis, , sizeof(dis));
dis[st] = ;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inque[u] = false;
for(int p = head[u]; p; p = next[p]) {
int v = to[p];
if(dis[v] < || dis[v] > dis[u] + cost[p]) {
dis[v] = dis[u] + cost[p];
//printf("%d %I64d\n",v,dis[v]);
if(!inque[v]) {
inque[v] = true;
Q.push(v);
}
}
}
}
} void addEdge(int u, int v, int c) {
to[ecnt] = v; cost[ecnt] = c;
next[ecnt] = head[u]; head[u] = ecnt++;
//printf("%d->%d %d\n",u,v,c);
//if(ecnt == MAXM) tle();
} void init(int ss, int tt) {
st = ss; ed = tt;
ecnt = ;
memset(head, , sizeof(head));
} LL solve() {
SPFA();
return dis[ed];
}
} G; const int M = MAXN * ; struct Tree {
int head[MAXN], inque[MAXN], c[MAXN], t[MAXN];
int next[M], to[M], cost[M];
int ecnt;
LL dis[MAXN]; void SPFA(int st) {
queue<int> Q;
Q.push(st);
memset(inque, , sizeof(inque));
memset(dis, , sizeof(dis));
dis[st] = ;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inque[u] = false;
for(int p = head[u]; p; p = next[p]) {
int v = to[p];
if(dis[v] < || dis[v] > dis[u] + cost[p]) {
dis[v] = dis[u] + cost[p];
//printf("%d %I64d\n",v,dis[v]);
if(!inque[v]) {
inque[v] = true;
Q.push(v);
}
}
}
}
} void addEdge(int u, int v, int cc) {
to[ecnt] = v; cost[ecnt] = cc;
next[ecnt] = head[u]; head[u] = ecnt++;
//printf("%d->%d %d\n",u,v,cc);
} void init() {
ecnt = ;
memset(head, , sizeof(head));
} void make_G() {
for(int i = ; i <= n; ++i) {
SPFA(i);
for(int j = ; j <= n; ++j) {
if(i == j) continue;
if(dis[j] >= && dis[j] <= t[i]) {
G.addEdge(i, j, c[i]);
}
}
}
}
} T; int main() {
int i;
while(scanf("%d%d", &n, &m) != EOF) {
scanf("%d%d", &x, &y);
G.init(x, y);
T.init();
int u, v, c;
for(i = ; i < m; ++i) {
scanf("%d%d", &u, &v);
scanf("%d", &c);
T.addEdge(u, v, c);
T.addEdge(v, u, c);
}
for(i = ; i <= n; ++i) {
scanf("%d", &T.t[i]);
scanf("%d", &T.c[i]);
}
T.make_G();
printf("%I64d\n", G.solve());
}
}

Codeforces 96D Volleyball(最短路径)的更多相关文章

  1. Codeforces 95C Volleyball(最短路)

    题目链接:http://codeforces.com/problemset/problem/95/C C. Volleyball time limit per test 2 seconds memor ...

  2. CF - 96D - Volleyball

    题意:一个无向图,有n个点,m条边,每条边有距离w,每个点有两个属性(1.从这点出发能到的最远距离,2.从这点出发的费用(不论走多远都一样)),一个人要从点x到点y,问最小费用是多少. 题目链接:ht ...

  3. Codeforces Beta Round #77 (Div. 1 Only) C. Volleyball (最短路)

    题目链接:http://codeforces.com/contest/95/problem/C 思路:首先dijkstra预处理出每个顶点到其他顶点的最短距离,然后如果该出租车到某个顶点的距离小于等于 ...

  4. 【codeforces 95C】Volleyball

    [题目链接]:http://codeforces.com/problemset/problem/95/C [题意] 给你n个点,m条边; 每个点有一辆出租车; 可以到达离这个点距离不超过u的点,且在这 ...

  5. Codeforces 601A:The Two Routes 宽搜最短路径

    A. The Two Routes time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  6. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  7. Codeforces Training S03E01泛做

    http://codeforces.com/gym/101078 和ysy.方老师一起打的virtual 打的不是很好...下面按过题顺序放一下过的题的题(dai)解(ma). A 给两个1~n的排列 ...

  8. Codeforces Round #130 (Div. 2) C. Police Station

    题目链接:http://codeforces.com/contest/208/problem/C 思路:题目要求的是经过1~N的最短路上的某个点的路径数 /  最短路的条数的最大值.一开始我是用spf ...

  9. Codeforces Round #103 (Div. 2) D. Missile Silos(spfa + 枚举边)

    题目链接:http://codeforces.com/problemset/problem/144/D 思路:首先spfa求出中心点S到其余每个顶点的距离,统计各顶点到中心点的距离为L的点,然后就是要 ...

随机推荐

  1. ZooKeeper分布式

    1:zk的相关特性 1.一致性:数据一致性,数据按顺序分批入库. 2.原子性:事务要么都成功,要么都失败,不会局部化. 3.单一视图:客户端连接集群中的任一zk节点,数据都是一致的. 4.可靠性:每次 ...

  2. Oracle登录失败:监听程序当前无法识别连接描述符中请求的服务

    Oracle11g下载地址:https://pan.baidu.com/s/1p3RwLUTAl1Ys4yXmXJ3OVQ 安装步骤视频链接:https://pan.baidu.com/s/1c0FC ...

  3. 自己写的代码实现Session

    package com.zq.web.context.windows; import java.util.HashMap;import java.util.Map; import org.apache ...

  4. MapReduce序列化及分区的java代码示例

    概述 序列化(Serialization)是指把结构化对象转化为字节流. 反序列化(Deserialization)是序列化的逆过程.把字节流转为结构化对象. 当要在进程间传递对象或持久化对象的时候, ...

  5. Hadoop-Hive学习笔记(1)

    1. Hive什么 a.Hive是基于Hadoop的一个数据仓库工具(注意不是数据仓库),将结构化的数据文件映射成一张数据库表. b.Hive是SQL的解析引擎,可以把sql语句转换成MapReduc ...

  6. opencv3 学习一 - Visual Studio 配置

    Step 1 下载最新版的Opencv3.4.2,见图片中的网址,选择 Win Pack. Step 2 安装Opencv3 到指定目录,见图片,路径后面会用到. Step 3 把安装目录下的bin路 ...

  7. python之内存与编码的那点事

    一.初始编码 ASCII 码不支持中文 是py2版本中的默认编码 ​Unicode 万国码, 英文使用16位(即两个字节​),中文使用32位(四个字节) ​utf-8 美国最少使用八位(1字节), 欧 ...

  8. 在线升级python3.3版本

    1.sudo su 2.wget -P /usr/local  http://www.python.org/ftp/python/3.3.0/Python-3.3.0.tgz    #指定下载到目录/ ...

  9. Discuz被挂马 快照被劫持跳转该如何处理 如何修复discuz漏洞

    Discuz 3.4是目前discuz论坛的最新版本,也是继X3.2.X3.3来,最稳定的社区论坛系统.目前官方已经停止对老版本的补丁更新与升级,直接在X3.4上更新了,最近我们SINE安全在对其安全 ...

  10. 【8086汇编-Day7】关于多个段的程序的实验

    实验一 实验二 实验三 实验四 实验五 实验六 总结 在集成环境下,内存从0770段开始按照段的先后顺序和内容多少分配,并且分配的都是16的倍数 关于实际占用的空间公式的话其实极容易想到(假设有N个字 ...