您的位置:首页 > 其它

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: