【USACO】2009 Dec Cow Toll Paths 过路费

12 篇文章 0 订阅
2 篇文章 0 订阅

Cow Toll Paths 过路费


  • Description

约翰家有 N 片草地,编号为 1 到 N ,彼此之间由 M 条双向道路连接,第 i 条道路连接了 Ai 和 Bi,两片草地之间可能有多条道路,但没有道路会连接同一片草地,现有的道路可以保证任意两片草 地都是连通的。
有一天,约翰宣布奶牛走路要收过路费,只要奶牛走过第 i 条道路,就要收费 Li 元。此外,约 翰还要求每头奶牛购买牌照,他为每片草地设置了牌照标准,如果奶牛购买的牌照价格低于某片草地 的标准,她将被禁止进入那片草地。第 i 片草地的牌照标准为 Ci。
新政策一出,奶牛们敢怒不敢言,有 Q 头奶牛向你咨询最省钱的走路办法,第 i 头奶牛要从草地 Si 走到 Ti。请你帮她们算算,选择什么样的路线才能最省钱?

  • Input Format

第一行:三个整数 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

  • Output Format

第一行到第 Q 行:第 i 行有一个整数,表示从 Si 到 Ti 的最低费用是多少

  • Sample Input

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

  • Sample Output

8
9

  • Hint

最好办法分别是1 → 3 → 5 → 4和2 → 5 → 3


  • 分析

整理一下题意就是问你两点间路径加上路径上的最大点权之和最小是多少?
我们把先把点按点权从小到大排序,然后采用Floyd的做法,在维护Dist[i][j]的同时维护Ans[i][j]。
对于每次Floyd找到的中间点k,点权的最大值一定在i、j、k三者中。因为k是从小到大枚举的,所以目前路径中除了起点i和终点j外,k是点权最大的点了。


#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
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.w<b.w;}
int 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值