高玩小Q不仅喜欢玩寻宝游戏,还喜欢一款升级养成类游戏。在这个游戏的世界地图中一共有nn个城镇,编号依次为11到nn。
这些城镇之间有mm条单向道路,第ii 条单项道路包含四个参数ui,vi,ai,biui,vi,ai,bi,表示一条从uiui号城镇出发,在vivi号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从vivi沿着该道路走到uiui。小Q的初始等级levellevel为11,每当试图经过一条道路时,需要支付cost=log2level+ailevelcost=log2level+ailevel点积分,并且经过该道路后,小Q的等级会提升aiai级,到达level+ailevel+ai级。但是每条道路都会在一定意义上歧视低消费玩家,准确地说,如果该次所需积分cost<bicost<bi,那么小Q不能经过该次道路,也不能提升相应的等级。
注意:本游戏中等级为正整数,但是积分可以是任意实数。
小Q位于11号城镇,等级为11,现在为了做任务要到nn号城镇去。这将会是一次奢侈的旅行,请写一个程序帮助小Q找到需要支付的总积分最少的一条路线,或判断这是不可能的。
这些城镇之间有mm条单向道路,第ii 条单项道路包含四个参数ui,vi,ai,biui,vi,ai,bi,表示一条从uiui号城镇出发,在vivi号城镇结束的单向道路,因为是单向道路,这不意味着小Q可以从vivi沿着该道路走到uiui。小Q的初始等级levellevel为11,每当试图经过一条道路时,需要支付cost=log2level+ailevelcost=log2level+ailevel点积分,并且经过该道路后,小Q的等级会提升aiai级,到达level+ailevel+ai级。但是每条道路都会在一定意义上歧视低消费玩家,准确地说,如果该次所需积分cost<bicost<bi,那么小Q不能经过该次道路,也不能提升相应的等级。
注意:本游戏中等级为正整数,但是积分可以是任意实数。
小Q位于11号城镇,等级为11,现在为了做任务要到nn号城镇去。这将会是一次奢侈的旅行,请写一个程序帮助小Q找到需要支付的总积分最少的一条路线,或判断这是不可能的。
Input第一行包含一个正整数T(1≤T≤30)T(1≤T≤30),表示测试数据的组数。
每组数据第一行包含两个整数n,m(2≤n≤100000,1≤m≤200000)n,m(2≤n≤100000,1≤m≤200000),表示城镇数和道路数。
接下来mm行,每行四个整数ui,vi,ai,bi(1≤ui,vi≤n,ui≠vi,0≤ai≤109,0≤bi≤60)ui,vi,ai,bi(1≤ui,vi≤n,ui≠vi,0≤ai≤109,0≤bi≤60),分别表示每条单向道路。Output对于每组数据,输出一行一个整数,即最少所需的总积分的整数部分,如:4.99994.9999输出44,1.01.0输出11。若不存在合法路线请输出−1−1。Sample Input
1 3 3 1 2 3 2 2 3 1 6 1 3 5 0
Sample Output
2
题意:
给你n个点,m条边,每条边有u,v,a,b这四个值,初始等级为1.问你从1点到n点需要花费的最小积分
题解:
每次走过一条路i 的消费是 log2(( level i +ai)/(level i) ) 式子可以转化为log2( ai + level i) - log2( level i),所以每次的消费就是log2( ai + level i) - log2( level i),如果走两条路,从1到v1再到v2 :那么消费就是
log2(a1+ level1) - log2( level 1)+log2(a2+ level2)-log2(level2), 因为level2就是level1+a1,所以可以化简为- log2( level 1)+log2(a2+ level2),如果把这个式子扩长,可以发现中间的部分都可以通过一加一减化掉,只剩下-log2(1)+log2(level n) 因为log2(1)==0 所以只要求得到n时的最小等级leveln,对其求log2(level n)就是结果最小等级就可以直接用Dijkstra求最短路求得
思路参考链接:https://blog.csdn.net/chimchim04/java/article/details/90068314
我的出错点1:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<queue> #include<vector> #include<math.h> using namespace std; const int INF=0x3f3f3f3f; const int maxn=2e5+5; typedef long long ll; const ll MAX=1e17; const ll inf=(ll)1<<61; struct shudui1 { ll start,value; bool operator < (const shudui1 q)const { return value>q.value; //最短路模板中这里应该是大于号,我写成了小于号 } } str1;
下面代码就是这个原因错的:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<math.h> 8 using namespace std; 9 const int INF=0x3f3f3f3f; 10 const int maxn=2e5+5; 11 typedef long long ll; 12 const ll MAX=1e17; 13 const ll inf=(ll)1<<61; 14 struct shudui1 15 { 16 ll start,value; 17 bool operator < (const shudui1 q)const 18 { 19 return value<q.value; 20 } 21 } str1; 22 struct node 23 { 24 ll a,v,nex,b; 25 } e[maxn]; 26 ll tot,v[maxn],p[70],vis[maxn],head[maxn]; 27 void add(ll u,ll v,ll a,ll b) 28 { 29 e[tot].v=v,e[tot].a=a,e[tot].b=b; 30 e[tot].nex=head[u]; 31 head[u]=tot++; 32 //printf("%d %d ",tot-1,v); 33 } 34 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数 35 void JK(ll s) 36 { 37 v[s]=1; 38 str1.start=s; 39 str1.value=1; 40 r.push(str1); 41 while(!r.empty()) 42 { 43 44 ll x,y; 45 str1=r.top(); 46 r.pop(); 47 x=str1.start; 48 y=str1.value; 49 //printf("%lld*** ",x); 50 if(vis[x]) continue; 51 vis[x]=1; 52 //printf("**%lld ",len); 53 for(ll i=head[x]; i!=-1; i=e[i].nex) 54 { 55 56 ll vv=e[i].v,a=e[i].a,b=e[i].b; 57 ll temp=1+a/v[x]; 58 //printf("%lld %lld ",temp,p[b]); 59 if(temp<p[b]) continue; 60 //printf("%lld %lld ",v[x]+v,v[vv]); 61 if((v[x]+a<v[vv])) 62 { 63 //printf("**"); 64 v[vv]=v[x]+a; 65 str1.start=vv; 66 str1.value=v[vv]; 67 r.push(str1); 68 } 69 } 70 } 71 } 72 int main() 73 { 74 // double xx=1.99; 75 // printf("%.0lf ",xx); 76 ll t; 77 p[0]=1; 78 for(ll i=1; i<=60; ++i) 79 p[i]=(ll)p[i-1]*(ll)2; 80 scanf("%lld",&t); 81 while(t--) 82 { 83 memset(head,-1,sizeof(head)); 84 tot=0; 85 ll n,m; 86 scanf("%lld%lld",&n,&m); 87 for(ll i=1; i<=n; ++i) 88 v[i]=inf,vis[i]=0; 89 while(m--) 90 { 91 ll x,y,z1,z2; 92 scanf("%lld%lld%lld%lld",&x,&y,&z1,&z2); 93 add(x,y,z1,z2); 94 } 95 JK(1); 96 if(v[n]>=inf) printf("-1 "); 97 else 98 { 99 double x=log2(v[n]); 100 printf("%lld ",(ll)x); 101 } 102 } 103 return 0; 104 }
出错点2:
while(!r.empty()) { ll x,y; str1=r.top(); r.pop(); x=str1.start; y=str1.value; //printf("%lld*** ",x); if(vis[x]) continue; vis[x]=1; //printf("**%lld ",len); for(ll i=head[x]; i!=-1; i=e[i].nex) { ll vv=e[i].v,a=e[i].a,b=e[i].b; ll temp=1+a/v[x]; //最短路算法里面这里应该是除于v[x],我却写成了str1.value //printf("%lld %lld ",temp,p[b]); if(temp<p[b]) continue; //printf("%lld %lld ",v[x]+v,v[vv]); if((v[x]+a<v[vv])) { //printf("**"); v[vv]=v[x]+a; str1.start=vv; str1.value=v[vv]; r.push(str1); } } }
原代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<math.h> 8 using namespace std; 9 const int INF=0x3f3f3f3f; 10 const int maxn=2e5+5; 11 typedef long long ll; 12 const ll MAX=1e17; 13 const ll inf=(ll)1<<61; 14 struct shudui1 15 { 16 ll start,value; 17 bool operator < (const shudui1 q)const 18 { 19 return value>q.value; //这里是大于号 20 } 21 } str1; 22 struct node 23 { 24 ll a,v,nex,b; 25 } e[maxn]; 26 ll tot,v[maxn],p[70],vis[maxn],head[maxn]; 27 void add(ll u,ll v,ll a,ll b) 28 { 29 e[tot].v=v,e[tot].a=a,e[tot].b=b; 30 e[tot].nex=head[u]; 31 head[u]=tot++; 32 //printf("%d %d ",tot-1,v); 33 } 34 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数 35 void JK(ll s) 36 { 37 v[s]=1; 38 str1.start=s; 39 str1.value=1; 40 r.push(str1); 41 while(!r.empty()) 42 { 43 44 ll x,y; 45 str1=r.top(); 46 r.pop(); 47 x=str1.start; 48 y=str1.value; 49 //printf("%lld*** ",x); 50 if(vis[x]) continue; 51 vis[x]=1; 52 //printf("**%lld ",len); 53 for(ll i=head[x]; i!=-1; i=e[i].nex) 54 { 55 56 ll vv=e[i].v,a=e[i].a,b=e[i].b; 57 ll temp=1+a/v[x];//最短路算法里面这里应该是除于v[x],我却写成了str1.value 58 //printf("%lld %lld ",temp,p[b]); 59 if(temp<p[b]) continue; 60 //printf("%lld %lld ",v[x]+v,v[vv]); 61 if((v[x]+a<v[vv])) 62 { 63 //printf("**"); 64 v[vv]=v[x]+a; 65 str1.start=vv; 66 str1.value=v[vv]; 67 r.push(str1); 68 } 69 } 70 } 71 } 72 int main() 73 { 74 // double xx=1.99; 75 // printf("%.0lf ",xx); 76 ll t; 77 p[0]=1; 78 for(ll i=1; i<=60; ++i) 79 p[i]=(ll)p[i-1]*(ll)2; 80 scanf("%lld",&t); 81 while(t--) 82 { 83 memset(head,-1,sizeof(head)); 84 tot=0; 85 ll n,m; 86 scanf("%lld%lld",&n,&m); 87 for(ll i=1; i<=n; ++i) 88 v[i]=inf,vis[i]=0; 89 while(m--) 90 { 91 ll x,y,z1,z2; 92 scanf("%lld%lld%lld%lld",&x,&y,&z1,&z2); 93 add(x,y,z1,z2); 94 } 95 JK(1); 96 if(v[n]>=inf) printf("-1 "); 97 else 98 { 99 double x=log2(v[n]); 100 printf("%lld ",(ll)x); 101 } 102 } 103 return 0; 104 }
整理之后的代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<math.h> 8 using namespace std; 9 const int INF=0x3f3f3f3f; 10 const int maxn=2e5+5; 11 typedef long long ll; 12 const ll MAX=1e17; 13 const ll inf=(ll)1<<61; 14 struct shudui1 15 { 16 ll v,c; 17 shudui1(ll x=0,ll y=0):v(x),c(y) {} 18 bool operator < (const shudui1 q)const 19 { 20 return c>q.c; 21 } 22 } str1; 23 struct node 24 { 25 ll a,v,nex,b; 26 } e[maxn]; 27 ll tot,dis[maxn],p[70],vis[maxn],head[maxn]; 28 void add(ll u,ll v,ll a,ll b) 29 { 30 e[tot].v=v,e[tot].a=a,e[tot].b=b; 31 e[tot].nex=head[u]; 32 head[u]=tot++; 33 //printf("%d %d ",tot-1,v); 34 } 35 priority_queue<shudui1>r; //里面的数据默认是从小到大排序,这样就不用通过for循环遍历在每一次找v里面的最小值,可以直接找到最小值,减少代码运行次数 36 void JK(ll s,ll n) 37 { 38 39 dis[s]=1; 40 str1.v=s; 41 str1.c=1; 42 r.push(str1); 43 while(!r.empty()) 44 { 45 str1=r.top(); 46 r.pop(); 47 int u=str1.v; 48 if(vis[u]) continue; 49 vis[u]=1; 50 //printf("%d %lld ",u,dis[u]); 51 for(int i=head[u]; i!=-1; i=e[i].nex) 52 { 53 int v=e[i].v; 54 //printf(" %d ",v); 55 ll a=e[i].a,b=p[e[i].b]; 56 if(a/dis[u]+1<b) continue; 57 if(dis[v]>a+dis[u]) 58 { 59 dis[v]=a+dis[u]; 60 r.push(shudui1(v,dis[v])); 61 } 62 } 63 } 64 if(dis[n]>=inf) printf("-1 "); 65 else 66 { 67 double x=log2(dis[n]); 68 printf("%d ",(int)x); 69 } 70 } 71 int main() 72 { 73 ll n,m; 74 p[0]=1; 75 for(ll i=1; i<=60; i++) 76 p[i]=(ll)p[i-1]*(ll)2; 77 ll t; 78 scanf("%lld",&t); 79 while(t--) 80 { 81 tot=0; 82 scanf("%lld%lld",&n,&m); 83 for(ll i=0; i<=n; i++) 84 { 85 vis[i]=0; 86 dis[i]=inf; 87 } 88 memset(head,-1,sizeof(head)); 89 ll x,y,b,a; 90 for(ll i=0; i<m; i++) 91 { 92 scanf("%lld %lld %lld %lld",&x,&y,&a,&b); 93 add(x,y,a,b); 94 } 95 JK(1,n); 96 } 97 return 0; 98 }