Flight Discount

题目描述

Your task is to find a minimum-price flight route from Syrjälä to Metsälä. You have one discount coupon, using which you can halve the price of any single flight during the route. However, you can only use the coupon once.

When you use the discount coupon for a flight whose price is x, its price becomes (it is rounded down to an integer).

输入

The first input line has two integers n and m: the number of cities and flight connections. The cities are numbered 1,2,...,n. City 1 is Syrjälä, and city n is Metsälä.

After this there are m lines describing the flights. Each line has three integers a, b, and c: a flight begins at city a, ends at city b, and its price is c. Each flight is unidirectional.

You can assume that it is always possible to get from Syrjälä to Metsälä.

Constraints

2 ≤ n ≤ 105

1 ≤ m ≤ 2*10^5

1 ≤ a,b ≤ n

1 ≤ c ≤ 109

输出

Print one integer: the price of the cheapest route from Syrjälä to Metsälä.

样例输入
复制代码
3 4
1 2 3
2 3 1
1 3 7
2 1 5
样例输出
复制代码
2

**题目大意:**要从1到n,有一张优惠券,可以让在1到n途中的某条路的价格变为一半(向下取整),求从1到n最小的价格

**思路:**dijkstra求最短路。加上优惠券,那就让d再多一个维度,用d[i][j]记录从1到i,j=0:还未使用优惠券时的最小价格,j=1:已经使用过优惠券的最小价格。

注意剪枝(即dijkstra模板中的s数组):加进队列中的这个价格(距离)已经更新过了

cpp 复制代码
if(dist>d[id][flag])
        continue;

代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using tup=tuple<ll,int,int>;//距离,节点编号,是否用券
const int N=100010,M=200010;
int h[N],e[M],ne[M],idx;
ll w[M],d[N][2];//到节点i,0:不使用优惠券,1:使用
void add(int a,int b,int c){
    w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n,m;cin>>n>>m;
    memset(h,-1,sizeof(h));
    for (int i=0;i<m;i++){
        int a,b,c;cin>>a>>b>>c;
        add(a,b,c);
    }
    memset(d,0x3f,sizeof(d));
    d[1][0]=0;
    priority_queue<tup,vector<tup>,greater<tup>>pq;
    pq.emplace(0,1,0);
    while(!pq.empty()){
        auto [dist,id,flag]=pq.top();
        pq.pop();
        if(dist>d[id][flag])
        continue;
        for (int i=h[id];i!=-1;i=ne[i]){
            int j=e[i];
            if(flag==0){//还没有使用券
                //不用券
                if(d[j][0]>dist+w[i]){
                    d[j][0]=dist+w[i];
                    pq.emplace(d[j][0],j,0);
                }
                //用券
                if(d[j][1]>dist+w[i]/2){
                    d[j][1]=dist+w[i]/2;
                    pq.emplace(d[j][1],j,1);
                }
            }
            else{//已经使用了券
                if(d[j][1]>dist+w[i]){
                    d[j][1]=dist+w[i];
                    pq.emplace(d[j][1],j,1);
                }
            }
        }
    }
    cout<<min(d[n][0],d[n][1]);
}
相关推荐
灵感__idea7 小时前
Hello 算法:贪心的世界
前端·javascript·算法
澈2078 小时前
深入浅出C++滑动窗口算法:原理、实现与实战应用详解
数据结构·c++·算法
ambition202428 小时前
从暴力搜索到理论最优:一道任务调度问题的完整算法演进历程
c语言·数据结构·c++·算法·贪心算法·深度优先
cmpxr_8 小时前
【C】原码和补码以及环形坐标取模算法
c语言·开发语言·算法
qiqsevenqiqiqiqi8 小时前
前缀和差分
算法·图论
代码旅人ing9 小时前
链表算法刷题指南
数据结构·算法·链表
Yungoal9 小时前
常见 时间复杂度计算
c++·算法
不爱吃炸鸡柳10 小时前
单链表专题(完整代码版)
数据结构·算法·链表
CylMK10 小时前
题解:AT_abc382_d [ABC382D] Keep Distance
算法
Dfreedom.10 小时前
计算机视觉全景图
人工智能·算法·计算机视觉·图像算法