D. Volleyball
http://codeforces.com/contest/96/problem/D
题意:
n个路口,m条双向路,每条长度为w。每个路口有一个出租车司机,最多可以乘坐这辆车走长度只要坐他的车,就必须交c元,最多可以载你走的长度为t的路。问从x到y的最小花费是多少。
分析:
第一遍SPFA求出每个点它能到的所有点,边权就是乘坐出租车的费用,第二遍直接跑最短路。稀疏图用了spfa
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline int read() { 17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 19 } 20 21 const int N = 1005; 22 23 struct ShortestPath{ 24 int head[N], len[N * N], nxt[N * N], to[N * N], q[N * N], En; 25 LL dis[N], INF; 26 bool vis[N]; 27 void add_edge(int u,int v,int w) { 28 ++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En; 29 } 30 void spfa(int S) { 31 memset(dis, 0x3f, sizeof(dis)); INF = dis[0]; 32 int L = 1, R = 0; 33 dis[S] = 0; q[++R] = S; vis[S] = true; 34 while (L <= R) { 35 int u = q[L ++]; vis[u] = false; 36 for (int i = head[u]; i; i = nxt[i]) { 37 int v = to[i]; 38 if (dis[v] > dis[u] + len[i]) { 39 dis[v] = dis[u] + len[i]; 40 if (!vis[v]) q[++R] = v, vis[v] = true; 41 } 42 } 43 } 44 } 45 }G1, G2; 46 47 int main() { 48 int n = read(), m = read(), S = read(), T = read(); 49 for (int i = 1; i <= m; ++i) { 50 int u = read(), v = read(), w = read(); 51 G1.add_edge(u, v, w); G1.add_edge(v, u, w); 52 } 53 for (int i = 1; i <= n; ++i) { 54 int d = read(), c = read(); 55 G1.spfa(i); 56 for (int j = 1; j <= n; ++j) { 57 if (G1.dis[j] <= d && i != j) G2.add_edge(i, j, c); // 此处为单向边 58 } 59 } 60 G2.spfa(S); 61 if (G2.dis[T] == G2.INF) puts("-1"); 62 else cout << G2.dis[T]; 63 return 0; 64 }