【2018CCPC女生赛】奢侈的旅行 HDU 6290

题目: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初始化,最后发现问题恰恰在这。

猜你喜欢

转载自blog.csdn.net/Vermouth_X/article/details/80500016