奢侈的旅行
Time Limit: 14000/7000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others)Total Submission(s): 592 Accepted Submission(s): 121
Problem Description
高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏。在这个游戏的世界地图中一共有
n
个城镇,编号依次为
1
到
n
。
这些城镇之间有 m 条单向道路,第 i 条单项道路包含四个参数ui ,vi,ai,bi ,表示一条从 ui 号城镇出发,在 vi 号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从 vi 沿着该道路走到 ui 。小Q的初始等级 level 为 1 ,每当试图经过一条道路时,需要支付 cost=log2((level+ai)/level) 点积分,并且经过该道路后,小Q的等级会提升 ai 级,到达 level + ai 级。但是每条道路都会在一定意义上歧视低消费玩家,准确地说,如果该次所需积分 cost < bi ,那么小Q不能经过该次道路,也不能提升相应的等级。
注意:本游戏中等级为正整数,但是积分可以是任意实数。
小Q位于 1 号城镇,等级为 1 ,现在为了做任务要到 n 号城镇去。这将会是一次奢侈的旅行,请写一个程序帮助小Q找到需要支付的总积分最少的一条路线,或判断这是不可能的。
这些城镇之间有 m 条单向道路,第 i 条单项道路包含四个参数ui ,vi,ai,bi ,表示一条从 ui 号城镇出发,在 vi 号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从 vi 沿着该道路走到 ui 。小Q的初始等级 level 为 1 ,每当试图经过一条道路时,需要支付 cost=log2((level+ai)/level) 点积分,并且经过该道路后,小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<=10^9,0<=bi<=60), 分别表示每条单向道路。
每组数据第一行包含两个整数 n,m(2<=n<=100000,1<=m<=200000) ,表示城镇数和道路数。
接下来 m 行,每行四个整数 ui ,vi,ai,bi(1<=ui,vi<=n,ui!=vi,0<=ai<=10^9,0<=bi<=60), 分别表示每条单向道路。
Output
对于每组数据,输出一行一个整数,即最少所需的总积分的整数部分,如:4.9999
输出4,1.0输出1
。若不存在合法路线请输出-1
。
Sample Input
13 31 2 3 22 3 1 61 3 5 0
Sample Output
2
思路:仔细观察那个cost的公式,所有的cost相加之后,利用对数公式log(x*y)=log(x)+log(y),可以发现cost=log(终点的等级)。所以只需要到达终点的时候,等级尽可能的低就行了,那么就是堆优化的最短路了。
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+10;
typedef long long ll;
struct lenka
{
ll x,le;
int operator<(const lenka& q)const{return q.le<le;}
};
struct EDG
{
int to,next,a,b;
}ed[MAX];
int head[MAX],tot;
ll d[MAX];
void add(int x,int y,int a,int b)
{
ed[tot].to=y;
ed[tot].a=a;
ed[tot].b=b;
ed[tot].next=head[x];
head[x]=tot++;
}
void bfs()
{
d[1]=1;
priority_queue<lenka>p;
p.push((lenka){1,1});
while(!p.empty())
{
lenka now=p.top();p.pop();
if(now.le!=d[now.x])continue;
for(int i=head[now.x];i!=-1;i=ed[i].next)
{
int nex=ed[i].to;
if((1ll<<ed[i].b)>1+ed[i].a/now.le)continue;//没有了精度误差的问题
if(d[nex]!=-1&&d[nex]<=now.le+ed[i].a)continue;
d[nex]=now.le+ed[i].a;
p.push((lenka){nex,d[nex]});
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
tot=0;
for(int i=1;i<=n;i++)head[i]=-1;
while(m--)
{
int x,y,a,b;
scanf("%d%d%d%d",&x,&y,&a,&b);
add(x,y,a,b);
}
for(int i=1;i<=n;i++)d[i]=-1;
bfs();
for(int i=0;i<=62;i++)
{
if((1ll<<i)>d[n])//没有了精度误差的问题
{
printf("%d\n",i-1);
break;
}
}
}
return 0;
}