HDU 6290 堆优化的dijkstra

题目连接

题意:

初始level为1由点1出发,n个点,m条边的有向图,对于每一条边由四个值u,v,a,b描述(a表示经过该边后等级提升数,b表示通过此边需要的最小过路费)。求1到n的最小花费。

思路:

首先看看过路费情况log2[(a+level)/level]>=b,等价于a/level>=2^b-1,由此可以看出level越小越有利于过路。

其次看看最终花费情况假设总共经过k条边到达终点那么最终过路费x = log2(1+a1)+log2((1+a1+2a)/(1+a1))+...log2((1+a1+a2+...+ak)/(1+a1+a2+...+ak-1)),等价于log2(1+a1+a2+...+ak),由此可以看出level越小最终花费也最小。

堆优化dijkstra以level为权值b为限制做最短路,即可获得答案。

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
const int maxm = 200010;
const long long inf = 1e18;

int n,m,tol,head[maxn];
struct edge
{
    int to,next; long long a,b;
}es[maxm];

void init()
{
    tol = 0; memset( head , -1 , sizeof(head) );
}

void addedge( int u , int v , long long a , long long b )
{
    es[tol].to = v;
    es[tol].next = head[u];
    es[tol].a = a;
    es[tol].b = b;
    head[u] = tol++;
}

int vis[maxn]; long long dis[maxn];

struct node
{
    int pos; long long dis;
    friend bool operator<( const node&a , const node&b )
    {
        return a.dis>b.dis;
    }
};

void dijkstra()
{
    for ( int i=1 ; i<=n ; i++ )
        vis[i] = 0,dis[i] = inf;
    priority_queue<node>Q;
    node p,q;
    p.pos = 1;
    p.dis = 1;
    Q.push(p);
    dis[1] = 1;
    while ( !Q.empty() )
    {
        p = Q.top();
        Q.pop();
        int u = p.pos;
        if ( vis[u] ) continue;
        vis[u] = 1;
        for ( int i=head[u] ; i!=-1 ; i=es[i].next )
        {
            int v = es[i].to; long long w = es[i].a;
            if ( w/dis[u]<es[i].b ) continue;
            if ( dis[v]>dis[u]+w  )
            {
                dis[v] = dis[u]+w;
                q.pos = v;
                q.dis = dis[v];
                Q.push(q);
            }
        }
    }
}

int main()
{
    int T; scanf ( "%d" , &T );
    while ( T-- )
    {
        init(); scanf ( "%d%d" , &n , &m );
        int u,v; long long a,b;
        for ( int i=1 ; i<=m ; i++ )
        {
            scanf  ( "%d%d%lld%lld" , &u , &v , &a , &b );
            addedge( u , v , a , ((long long)1<<b)-1 );
        }
        dijkstra();
        if ( dis[n]==inf )
            printf ( "-1\n" );
        else
            printf ( "%d\n" , (int)log2(dis[n]*1.0) );
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值