2019西安icpc邀请赛M题 Travel (迪杰斯特拉算法+正常优化)

dis数组里面存到此点的最少需要的等级,没到一个点就对其他点进行松弛操作,太久没写最短路了,松弛操作忘了最重要的一步,levpass是通过u到v此边需要的最少等级,所以dis[v]应该是和到达u点且通过u-v边的最少等级进行松弛,就是这里gg,拿铁一杯~,还有坑点就是双向边数组开两倍,用longlong,输出的时候可能会超。

这个比二分加最短路的快挺多了,就是计蒜客只有20组数据卡不掉,二分加最短路大概要250左右,我的只有60。

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<ctime>
#include<algorithm>
#define eps 1e-14
#define pi acos(-1)
#define ll long long
#define RD T*(rand()*2-RAND_MAX)
#define Drand (long double)rand()/RAND_MAX
#define INF 0x3f3f3f3f
#define endl '\n'
using namespace std;
const int maxn=2e5+10;
const int mod=1e4+7;

ll head[maxn],tot=0,dis[maxn],nod[maxn];
ll n,m,c,d,e;

struct nn
{
    ll v,w,nex;
}l[maxn];

struct mm
{
    ll u,lev,cnt;
    mm(){}
    mm(ll _u,ll _lev,ll _cnt):u(_u),lev(_lev),cnt(_cnt){}
    bool operator < (const mm & a)const
    {
        return lev>a.lev;
    }
};

void addline(ll u,ll v,ll w)
{
    l[tot].nex=head[u];
    l[tot].v=v;
    l[tot].w=w;
    head[u]=tot;
    tot++;
}

ll dij()
{
    memset(dis,INF,sizeof dis);
    memset(nod,0,sizeof nod);
    priority_queue<mm>q;
    q.push(mm(1,0,0));
    dis[1]=0;
    while(!q.empty()){
        mm now=q.top();
//        cout<<now.u<<endl;
        q.pop();
        if(nod[now.u])continue;
        nod[now.u]=1;
        for(ll i=head[now.u];i!=-1;i=l[i].nex){
            ll v=l[i].v;
            ll levd=l[i].w%d==0 ? l[i].w/d : l[i].w/d+1;
            ll levcnt=(now.cnt+1)%e==0 ? (now.cnt+1)/e : (now.cnt+1)/e+1;
            ll levpass=max(levd,levcnt);
//            cout<<now.u<<" "<<v<<" "<<dis[v]<<" "<<levpass<<endl;
            levpass=max(dis[now.u],levpass);
            dis[v]=min(dis[v],levpass);
            if(nod[v]==0)q.push(mm(l[i].v,dis[v],now.cnt+1));
        }
    }
    return dis[n];
}

int main()
{
//    freopen("in.txt","r",stdin);
    memset(head,-1,sizeof head);
    scanf("%lld%lld%lld%lld%lld",&n,&m,&c,&d,&e);
    while(m--){
        ll a1,a2,a3;
        scanf("%lld%lld%lld",&a1,&a2,&a3);
        addline(a1,a2,a3);
        addline(a2,a1,a3);
    }
    ll ans=dij();
    if(ans==INF)cout<<-1<<endl;
    else cout<<ans*c<<endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值