#bzoj2934#【重庆市NOIP模拟赛】业务(SPFA / Dijk)
2017-07-24 16:49
162 查看
2934: 【重庆市NOIP模拟赛】业务
时间限制:1 Sec 内存限制:128 MB
题目描述
Mr_H 谋得一份兼职——货车司机,从此以后他将会开着货车穿行在 C 国的各大城市之间。C 国中有 n 座城市(编号为 1~n),并且有 m 条双向公路,每条公路连接两座不同的城市。货车
从任意一座城市出发都可以抵达任意另一座城市。在每条公路上,都有一个收费站,通过的车辆需要
交纳一定过路费。可能有多条公路连接相同的两座城市。
为了增加财政收入,C 国还在每座城市也设置了收费站。并且规定,车辆从一座城市到另一座城
市的费用是,所经过公路费用和,加上所经过的城市中费用的次大值
...(这里的次大可以和最大相同,
但是城市不同)。
(这里的次大可以和最大相同,
但是城市不同)。
现在 Mr_H 告诉你今年 k 次业务运送货物的起点、终点城市列表,请你帮忙计算,每次业务需要
交纳的最低过路费。
输入
第一行包含三个用一个空格隔开的整数:n,m,k。其意义如题目描述。第 2 到第 n+1 行:第 i+1 行包含一个单独的整数 c(1<=c<=100000),表示城市 i 的费用。
接下来的 m 行,每行包含三个整数 a,b,w,表示一条公路连接城市 a 和城市 b(1<=a,b<=n),
其过路费为 w(1<=w<=100000)。
最后的 k 行,每行包含两个整数:s,t,表示一次业务的起点和终点(1<=s,t<=n 且 s!=t)。
输出
共 k 行,每行一个整数,表示从城市 s 到 t 的最少过路费。样例输入
5 7 3 2 5 3 3 4 1 2 3 1 3 2 2 5 3 5 3 1 5 4 1 2 4 3 3 4 4 1 3 1 4 2 3
样例输出
4 7 8
提示
对于每个i到j,假设它们中间需要经过的城市中的次大城市是k
于是可以将i到j的路程分成两部分,从i到k和从k到j
那么可以知道将会产生两种情况(注意不可以并列,直接数出第二个):
一:i到k中k为次大城市 + j到k中k为最大城市
二:i到k中k为最大城市 + j到k中k为次大城市
定义Dis[i][0]为k是次大城市的最短路
Dis[i][1]为k是最大城市的最短路
Dis[i][0] = Dis[j][0] + len[i][j]
(P[k] >= P[i])
Dis[i][1] = Dis[j][1] + len[i][j]
(P[k] >= P[i])
Dis[i][0] = Dis[i][1] + len[i][j]
(P[k] < P[i])
注意,有人问了一个问题,我觉得挺有价值的。
下方给出的代码中,Dis[k][0]清的0,但是
Code:
#include<iostream>//枚举被作为次大值的城市k,直接强行处理出从k到所有点的距离,然后更新Cost[i][j] #include<cstdio>//Dis[i]表示从S到i的道路费用总和的最小值 #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int Maxn = 250; const int INF = 0x3f3f3f3f; struct node{ int v, cap, nxt; }edge[10005 << 1]; int N, M, K; int cnt; bool Inq[Maxn + 5]; int P[Maxn + 5], fir[Maxn + 5]; int Cost[Maxn + 5][Maxn + 5], Dis[Maxn + 5][2]; bool getint(int & num){ char c; int flg = 1; num = 0; while((c = getchar()) < '0' || c > '9'){ if(c == '-') flg = -1; } while(c >= '0' && c <= '9' ){ num = num * 10 + c - 48; c = getchar(); } num *= flg; return 1; } void addedge(int a, int b, int c){ edge[++ cnt].v = b, edge[cnt].cap = c, edge[cnt].nxt = fir[a], fir[a] = cnt; edge[++ cnt].v = a, edge[cnt].cap = c, edge[cnt].nxt = fir[b], fir[b] = cnt; } queue<int>Q; void SPFA(int S){ memset(Dis, 0x3f, sizeof Dis ); Dis[S][0] = Dis[S][1] = 0; Q.push(S); while(! Q.empty()){ int tmp = Q.front(); Q.pop(); Inq[tmp] = 0; for(int i = fir[tmp]; i; i = edge[i].nxt){ int v = edge[i].v; if(P[v] <= P[S]){ if(Dis[v][1] > Dis[tmp][1] + edge[i].cap){ Dis[v][1] = Dis[tmp][1] + edge[i].cap; if(! Inq[v]) Inq[v] = 1, Q.push(v); } if(Dis[v][0] > Dis[tmp][0] + edge[i].cap){ Dis[v][0] = Dis[tmp][0] + edge[i].cap; if(! Inq[v]) Inq[v] = 1, Q.push(v); } } else { if(Dis[v][0] > Dis[tmp][1] + edge[i].cap){ Dis[v][0] = Dis[tmp][1] + edge[i].cap; if(! Inq[v]) Inq[v] = 1, Q.push(v); } } } } } int main(){ //freopen("business.in", "r", stdin); //freopen("business.out", "w", stdout); getint(N), getint(M), getint(K); for(int i = 1; i <= N; ++ i) getint(P[i]); int a, b, c; for(int i = 1; i <= M; ++ i){ getint(a), getint(b), getint(c); addedge(a, b, c); } memset(Cost, 0x3f, sizeof Cost ); for(int k = 1; k <= N; ++ k){ SPFA(k); for(int i = 1; i <= N; ++ i) for(int j = i + 1; j <= N; ++ j) Cost[i][j] = Cost[j][i] = min(Cost[i][j], min(Dis[i][0] + Dis[j][1], Dis[i][1] + Dis[j][0]) + P[k]); } for(int i = 1; i <= K; ++ i) getint(a), getint(b), printf("%d\n", Cost[a][b]); return 0; }
相关文章推荐
- 【重庆市NOIP模拟赛】业务
- [noip模拟赛]邮递员送信(spfa)
- [noip模拟赛]旅行Pod(spfa)
- 【NOIP模拟赛】chess 建图+spfa统计方案数
- #bzoj2933#【重庆市NOIP模拟赛】数据(DP线段树优化 or DP堆优化 + 证明)
- #bzoj2932#【重庆市NOIP模拟赛】旅行(贪心 DP是不可以的!)
- CQBZOJ 【重庆市NOIP模拟赛】避难向导
- 【贪心】【枚举】【重庆市NOIP模拟赛】旅行
- 20151006重庆市NOIP模拟赛总结
- noip模拟赛 业务办理
- 【总结】20151017重庆市NOIP模拟赛
- 【重庆市NOIP模拟赛】数据
- SSL2864 【NOIP2013模拟联考15】物语(spfa优化)
- 【NOIP模拟赛】就 反悔贪心
- 【NOIP模拟赛】 permutation 数学(打表)
- 【NOIP 模拟赛】区间第K大(kth) 乱搞
- noip 模拟赛(by azui大爷) day2 t2(附O(1)求RMQ)
- 2017.08.15【NOIP提高组】模拟赛B组 单足跳
- 【jzoj5285】【NOIP提高组模拟赛A组8.16】【排序】
- 纪中训练 day2 【NOIP普及组】模拟赛D组 解题报告