题意:
初始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;
}