题目:http://acm.hdu.edu.cn/showproblem.php?pid=6290
官方题解:
比赛的时候是推出了公式的,奈何最后卡在TLE。
Q神放话:只要你敢写,我就敢卡
行吧,谁让人家是出题人呢。。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
typedef pair<LL,int>pa;
const int N=100005;
const LL INF=1LL<<60;
int n,m;
struct Edge{
int v;
LL a,b;
Edge(){}
Edge(int v,LL a,LL b):v(v),a(a),b(b){}
};
vector<Edge>edge[N];
LL Pow[65],dist[N];
void init(){
Pow[0]=1;
for(int i=1;i<=60;i++)
Pow[i]=2*Pow[i-1];
}
void dijkstra(int x){
for(int i=1;i<=n;i++)
dist[i]=INF;
priority_queue<pa,vector<pa>,greater<pa> >qu;
qu.push(pa(1,x));
dist[x]=1;
while(!qu.empty()){
pa u=qu.top();
qu.pop();
// cout<<u.second<<' '<<dist[u.second]<<' '<<u.first<<endl;
if(dist[u.second]<u.first)
continue;
for(int i=0;i<edge[u.second].size();i++){
int v=edge[u.second][i].v;
LL a=edge[u.second][i].a;
LL b=edge[u.second][i].b;
// cout<<v<<endl;
if(a/u.first>=b-1&&u.first+a<dist[v]){
dist[v]=u.first+a;
// cout<<v<<' '<<dist[v]<<endl;
qu.push(pa(dist[v],v));
}
}
}
}
int main(){
init();
int casen;
scanf("%d",&casen);
while(casen--){
scanf("%d%d",&n,&m);
int u,v;
LL a,b;
for(int i=0;i<m;i++){
scanf("%d%d%lld%lld",&u,&v,&a,&b);
edge[u].push_back(Edge(v,a,Pow[b]));
}
dijkstra(1);
LL k=dist[n];
if(k==INF)
printf("-1\n");
else{
LL ans=0;
while(k>1)
k/=2,ans++;
printf("%lld\n",ans);
}
if(casen){
for(int i=1;i<=n;i++)
edge[i].clear();
}
}
return 0;
}
前面一直在TLE,据出题人说如果dij内部不判断一个点是否走过,也会T
if(dist[u.second]<u.first)
continue;
也就是这里
贴一组样例:1
3 3
1 2 3 2
2 3 1 0
1 3 5 0
根据这组样例我们可以看到,刚开始会将(6,3)push进去,后面由1-2-3这条路会将dist[3]更新为5,而要使队列为空,一定会将(6,3)pop出来,若是不判断已经出现的点,如果3不是终点的话,那么这个本来就很大的答案(6>5)会进入后面的循环,从而会增加复杂度。
所以需要判一下,若当前已有更优的解,就可以省掉多余的步骤。
还有一个问题是 初始化。
我一开始以为会被覆盖掉,就没有将edge初始化,最后发现问题恰恰在这。