奢侈的旅行
Time Limit: 14000/7000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 1918 Accepted Submission(s): 400
Problem Description
高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏。在这个游戏的世界地图中一共有n个城镇,编号依次为1到n。
这些城镇之间有m条单向道路,第i 条单项道路包含四个参数ui,vi,ai,bi,表示一条从ui号城镇出发,在vi号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从vi沿着该道路走到ui。小Q的初始等级level为1,每当试图经过一条道路时,需要支付cost=log2level+ailevel点积分,并且经过该道路后,小Q的等级会提升ai级,到达level+ai级。但是每条道路都会在一定意义上歧视低消费玩家,准确地说,如果该次所需积分cost<bi,那么小Q不能经过该次道路,也不能提升相应的等级。
注意:本游戏中等级为正整数,但是积分可以是任意实数。
小Q位于1号城镇,等级为1,现在为了做任务要到n号城镇去。这将会是一次奢侈的旅行,请写一个程序帮助小Q找到需要支付的总积分最少的一条路线,或判断这是不可能的。
Input
第一行包含一个正整数T(1≤T≤30),表示测试数据的组数。
每组数据第一行包含两个整数n,m(2≤n≤100000,1≤m≤200000),表示城镇数和道路数。
接下来m行,每行四个整数ui,vi,ai,bi(1≤ui,vi≤n,ui≠vi,0≤ai≤109,0≤bi≤60),分别表示每条单向道路。
Output
对于每组数据,输出一行一个整数,即最少所需的总积分的整数部分,如:4.9999输出4,1.0输出1。若不存在合法路线请输出−1。
Sample Input
1 3 3 1 2 3 2 2 3 1 6 1 3 5 0
Sample Output
2
Source
解题思路
假设已经走了n条边,每条边对应a值为bi,那么当前的总花费为
log(1+b1) - log1 + log(1+b1+b2)-log(1+b1)...+log(1+b1+b2+...+bn) - log(1+b1+b2+...+bn-1)
=log(1+b1+b2+...+bn)
所以只要走过的路的a加起来最小,总花费就最小。且cost = log((level+ai)/level)=log(1+ai/level),所以level越小,对应的cost就越大,所以只要用a来当权值,用b来当限制条件求最短路就可以了。
代码如下
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
#include <cmath>
#define maxn 100005
using namespace std;
typedef long long ll;
struct R{
ll r, a, b;
R(ll r, ll a,ll b): r(r), a(a), b(b){ }
};
vector<R> g[maxn];
ll dis[maxn];
ll get(ll x)
{
ll k = 0;
ll r = 1;
while(r <= x){
k ++;
r *= 2;
}
return k - 1;
}
struct node{
ll x, w;
node(ll x, ll w): x(x), w(w){ }
bool operator<(const node& a)const{
return w > a.w;
}
};
int main()
{
int T;
scanf("%d", &T);
while(T --){
ll n, m;
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= m; i ++){
ll u, v, a, b;
scanf("%lld%lld%lld%lld", &u, &v, &a, &b);
g[u].push_back(R(v, a, b));
}
memset(dis, 0x3f, sizeof(dis));
priority_queue<node> que;
dis[1] = 1;
bool flg = false;
que.push(node(1, 1));
while(!que.empty()){
node top = que.top();
que.pop();
ll x = top.x;
if(x == n){
flg = true;
break;
}
if(top.w > dis[x])
continue;
for(int i = 0; i < g[x].size(); i ++){
ll a = g[x][i].a;
ll b = g[x][i].b;
ll r = g[x][i].r;
if(dis[x] + a < dis[r] && get(1 + a / dis[x]) >= b){
dis[r] = dis[x] + a;
que.push(node(r, dis[r]));
}
}
}
if(flg)
printf("%lld\n", get(dis[n]));
else
puts("-1");
for(int i = 1; i <= n; i ++)
g[i].clear();
}
return 0;
}