【USACO】2009 Feb Revamping Trails 道路翻新

12 篇文章 0 订阅
6 篇文章 0 订阅

Revamping Trails 道路翻新


  • Description

农场里有N个牛棚,编号为1到N。它们之间由M条双向道路连接,第i条道路连接的牛棚为 P1i P2i ,通行时间为 Ti 。约翰每天都要检查牛棚里的奶牛,他会从编号为1牛棚出发,通过最短的路线走到编号为N的牛棚。为了节约时间,约翰打算翻新K条道路,被翻新后的道路可以快速通过,通行时间视作0。请帮助约翰选择最好的翻新方法使得从1号牛棚到N号 牛棚的通行时间最短。

  • Input Format

第一行:三个用空格分开的整数: N M K 1N10000KM500001K20,第二行到M+1行:在第i+1行有三个用空格分开的整数: P1iP2i Ti ,表示第i条道路的情况, 1P1i,P2iN1Ti106

  • Output Format

第一行:翻新后的最短通行时间,输入数据保证终点一定可达

  • Sample Input

4 4 1
1 2 10
2 4 10
1 3 1
3 4 100

  • Sample Output

1

  • Hint

选择翻新3→4,通行时间从100变成0,最短路径为1→3→4,因而总用时为1。


  • 分析

因为K只有20的范围,所以我们可以从K入手。我们把一个点拆成K+1个点,分别表示走到这个点时已翻新了若干条道路,然后跑Spfa。
之后你会发现TLE,所以要堆优化。


#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,k,u,v,w,x,tot,ans=1<<30,last[10010],dist[21][10010],bo[21][10010];
struct info{
    int to,next,val;
}e[100010];
struct Date{
    int x,u;
};
inline bool operator < (const Date&a,const Date&b){return dist[a.x][a.u]>dist[b.x][b.u];}
priority_queue <Date> q;
void addline(int u,int v,int w){
    e[++tot].to=v; e[tot].val=w; e[tot].next=last[u]; last[u]=tot;
    e[++tot].to=u; e[tot].val=w; e[tot].next=last[v]; last[v]=tot;
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out1.txt","w",stdout);
    scanf("%d %d %d\n",&n,&m,&k);
    for (int i=1;i<=m;i++){
        scanf("%d %d %d\n",&u,&v,&w);
        addline(u,v,w);
    }
    for (int i=0;i<=k;i++)
        for (int j=0;j<=n;j++)
            dist[i][j]=1<<30;
    q.push((Date){0,1});
    bo[0][1]=1;
    dist[0][1]=0;
    int cas=0;
    for (;!q.empty();){
        x=q.top().x,u=q.top().u; q.pop(); cas++;
        bo[x][u]=0;
        for (int i=last[u];i;i=e[i].next){
            v=e[i].to,w=e[i].val;
            if (dist[x][u]+w<dist[x][v]){
                dist[x][v]=dist[x][u]+w;
                if (bo[x][v]==0){
                    bo[x][v]=1; q.push((Date){x,v});
                }
            }
            if (x+1<=k && dist[x][u]<dist[x+1][v]){
                dist[x+1][v]=dist[x][u];
                if (bo[x+1][v]) continue;
                bo[x+1][v]=1; q.push((Date){x+1,v});
            }
        }
    }
    printf("%d",dist[k][n]);
    fclose(stdin); fclose(stdout);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值