约翰家有 N 片草地,编号为 1 到 N ,彼此之间由 M 条双向道路连接,第 i 条道路连接了 Ai 和 Bi,两片草地之间可能有多条道路,但没有道路会连接同一片草地,现有的道路可以保证任意两片草 地都是连通的。
有一天,约翰宣布奶牛走路要收过路费,只要奶牛走过第 i 条道路,就要收费 Li 元。此外,约 翰还要求每头奶牛购买牌照,他为每片草地设置了牌照标准,如果奶牛购买的牌照价格低于某片草地 的标准,她将被禁止进入那片草地。第 i 片草地的牌照标准为 Ci。
新政策一出,奶牛们敢怒不敢言,有 Q 头奶牛向你咨询最省钱的走路办法,第 i 头奶牛要从草地 Si 走到 Ti。请你帮她们算算,选择什么样的路线才能最省钱?
第一行:三个整数 N ,M 和 Q,1 ≤ N ≤ 250; 1 ≤ M ≤ 10000; 1 ≤ Q ≤ 10000
第二行到第 N + 1 行:第 i + 1 行有一个整数 Ci,1 ≤ Ci ≤ 10^6
第 N + 2 行到第 N + M + 1 行:第 i + 1 行有三个整数 Ai,Bi 和 Li,1 ≤ Ai ; B i ≤ N ,1 ≤ Li ≤ 10^6
第 N + M +2 行到第 N + M + Q +1 行:第 i + N + M +1 行有两个整数 Si 和 Ti,1 ≤ Si,Ti ≤ N
第一行到第 Q 行:第 i 行有一个整数,表示从 Si 到 Ti 的最低费用是多少
5 7 2
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 4
2 3
8
9
最好办法分别是1 → 3 → 5 → 4和2 → 5 → 3
整理一下题意就是问你两点间路径加上路径上的最大点权之和最小是多少?
我们把先把点按点权从小到大排序,然后采用Floyd的做法,在维护Dist[i][j]的同时维护Ans[i][j]。
对于每次Floyd找到的中间点k,点权的最大值一定在i、j、k三者中。因为k是从小到大枚举的,所以目前路径中除了起点i和终点j外,k是点权最大的点了。
#include
#include
#include
#include
#include
using namespace std;
struct data{int id,w;}a[251];
int tot,n,m,q,u,v,w,last[10001],Dist[251][251],Ans[251][251],newid[251];
inline bool cmp(const data&a,const data&b){return a.wint main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
memset(Dist,127/2,sizeof(Dist));
memset(Ans,127/2,sizeof(Ans));
scanf("%d%d%d",&n,&m,&q);
for (int i=1;i<=n;i++){
scanf("%d",&a[i].w);
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++) newid[a[i].id]=i;
for (int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
u=newid[u],v=newid[v];
Dist[u][v]=Dist[v][u]=min(w,Dist[v][u]);
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++){
Dist[i][j]=min(Dist[i][j],Dist[i][k]+Dist[k][j]);
Ans[i][j]=min(Ans[i][j],Dist[i][j]+max(a[i].w,max(a[j].w,a[k].w)));
}
for (int i=1;i<=q;i++){
scanf("%d%d",&u,&v);
printf("%d\n",Ans[newid[u]][newid[v]]);
}
fclose(stdin); fclose(stdout);
return 0;
}