Hdu 6290 奢侈的旅行(最短路:dijkstra算法(邻近表优先队列解法))
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6290
这道题目限制点非常多,首先是在t极限为30的情况下,n最大为1e5,明显裸的迪杰斯特拉(3e11的时间复杂度,就算给了7秒也是一定会超时)是过不去的,但是因为道路数量限制在了2e5,那就可以用优先队列优化,极限复杂度也就是跑完所有道路
6e6的复杂度完全够了。
解题思路:dist数组用来保存到点的最低等级,初始化dist数组要注意,因为a<=1e9,那极限等级应该是99,999,000,000,000,初始化数据一定要比这个数大,这个坑点太深了,错了好久就是不知道哪错了,都怀疑精度丢失了,没想到题目给了这种坑点。然后因为城市数量太多,邻近矩阵空间复杂度太高,所以用邻近表写(空间复杂度就是城市数量),然后就是正常的迪杰斯特拉操作了,注意和搜索的区别就是vis标记数组在该点从队列弹出后在进行标记,保证这个点能走的所有路都会被遍历
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Edge{
int from,to,nex,a,b;
}edge[200005];
#define inf 0x3f3f3f3f3f3f3f //注意,inf的值一定要特别大 a的最大值是1e9,题目极限等级就是1e14,不能比1e14小
int head[100005],cnt=1,vis[100005];
ll dist[100005];
inline void add(int from,int to,int a,int b){
edge[cnt].from=from;
edge[cnt].to=to;
edge[cnt].a=a;
edge[cnt].b=b;
edge[cnt].nex=head[from];
head[from]=cnt;
cnt++;
}
inline ll read(){
ll res=0;
bool flag=true;
char c;
if((c=getchar())&&c=='-'){
flag=false;
}else if(c>='0'&&c<='9'){
res=c-'0';
}
while((c=getchar())&&c>='0'&&c<='9'){
res=(res<<3)+(res<<1)+c-'0';
}
return flag?res:-res;
}
inline void out(ll res){
if(res<0){
putchar('-');
res*=-1;
}
if(res>9)out(res/10);
putchar(res%10+'0');
}
int n,m;
struct node{
ll a,l;//当前位置,当前等级
friend bool operator < (const node &a,const node &b){
return a.l>b.l;
}
}now;
inline bool check(ll level,ll aa,ll bb){//判断满不满足题意
double l=level,a=aa,b=bb;
if(log2((1.0*l+a)/l)<1.0*b)return false;
return true;
}
inline void Dijkstra(){
for(int i=1;i<=n;i++){
dist[i]=inf;
}
dist[1]=1;//dist保存到i点的最低等级,相当于记忆化操作
priority_queue<node>q;
q.push(node{1,1});
while(!q.empty()){
now=q.top();
q.pop();
if(vis[now.a]==1)continue;//如果这个点已经标记过了,说明所有这个点的路都走过了,就没必要再来一次
vis[now.a]=1;
for(int i=head[now.a];i!=-1;i=edge[i].nex){
if(check(now.l,edge[i].a,edge[i].b)){//满足题意cast>=b
if(dist[edge[i].to]>dist[now.a]+edge[i].a){//通过当前点到下一个点是否等级会更低
dist[edge[i].to]=dist[now.a]+edge[i].a;//更新到这个点的最小等级
q.push(node{edge[i].to,dist[edge[i].to]});
}
}
}
}
if(dist[n]==inf){
out(-1);
}else{
out((ll)log2(dist[n]));
}
putchar('\n');
}
int main() {
int t=read();
while(t--){
n=read(),m=read();
for(int i=1;i<=n;i++){
head[i]=-1;
vis[i]=0;
}
cnt=1;
for(int i=0;i<m;i++){
int from=read(),to=read(),a=read(),b=read();
add(from,to,a,b);
}
Dijkstra();
}
return 0;
}