西安icpc邀请赛M. Travel

博客围绕一个算法问题展开,给定有n个点、m条边的图,每条边有长度。Alice的飞船初始为0级,可无限升级,每次升级有花费,升级后飞行距离和次数增加。需从1点到n点,求最小花费,若不能到达则输出 -1。解题思路是二分答案,用优先队列让边数少的先走。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意
有n个点,编号从1到n,有m条边,每条边有一个长度w。
Alice有一艘飞船,Alice可以给它升级很多次(无限),每升级一次需要花费c,升级一次之后飞船单次可飞行距离增加d,可飞行次数增加e。如果飞船需要飞过一条边,就需要满足单次可飞行距离≥这条路的长度同时可飞行次数不为0。
现在Alice在编号为1的点,她的飞船为0级,单次可飞行距离和可飞行次数都为0,请你求出最小的花费使得Alice可以到达n点,如果不能到达n则输出−1。
输入保证图联通,没有自环,没有重边

思路:
就是二分答案,有两个限制条件,用优先队列让边数少的先走,走过的点不再推入。

#include<bits/stdc++.h>
using namespace std;
const int inf = (1<<30);
typedef long long ll;
struct edge
{
    ll to,cost;
};
struct node
{
    ll dian;
    ll bian,maxdis;
    friend bool operator < (node n1, node n2)
    {
        return n1.bian>n2.bian;
    }
};
ll n,m,c,d,e,flag = 0;
vector<edge>q[111111];
int vis[111111];
bool judge(ll mid)
{
    ll dd = mid*d;
    ll ee = mid*e;
    memset(vis,0,sizeof(vis));
    priority_queue<node>p;
    node a;
    a.dian = 1;
    a.bian = 1;
    vis[1] = 1;
    a.maxdis = 0;
    p.push(a);
    while(!p.empty())
    {
        node now = p.top();
        if(now.dian==n)
        {
            if(now.bian<=ee)
            {
                flag = 1;
                return true;
            }
        }
        p.pop();
        for(int i = 0 ; i < q[now.dian].size() ; i ++)
        {
            node t;
            t.bian = now.bian + 1;
            t.dian = q[now.dian][i].to;
            t.maxdis = max(now.maxdis,q[now.dian][i].cost);
            if(t.maxdis<=dd && t.bian<=ee && !vis[t.dian])
            {
                p.push(t);
                vis[t.dian] = 1;
            }
        }
    }
    return false;
}
int main()
{
    cin >> n >> m;
    cin >> c >> d >> e;
    for(int i = 1 ; i <= m ; i ++)
    {
        ll a,b,d;
        scanf("%d%d%d",&a,&b,&d);
        q[a].push_back(edge{b,d});
        q[b].push_back(edge{a,d});
    }
    ll l = 1,r = 111111,mid,ans;
    while(l<=r)
    {
        mid = (l+r)>>1;
        //cout << l << " " << r << " " << mid << endl;
        if(judge(mid))
        {
            r = mid - 1;
            ans = mid;
        }
        else
        {
            l = mid + 1;
        }
    }
    if(flag)
        cout << ans*c << endl;
    else
        cout << -1 << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值