HDU6705 path(贪心+优先队列)

首先我们发现因为每条边无限用,因此会有一种优先队列贪心的基本思路。只要每次弹出最小的路径就是答案。

但是如果每次都将所有边存入,取出最小边后又存入,这样会导致内存爆炸并且超时。

所以我们要想办法是否可以存一些必要的可能成为答案的边,首先我们将以i开始的边都存到对应的vector中

如果我们从优先队列中取出一条边,我们发现,可能成为答案的边除了本身就在队列中的边外,还有可能是以终点扩展出的最小边,以及以边长度在出发点出去的并且长度比这条边大的边。

每次只要这样维护即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
struct edge{
    ll to,w;
    bool operator <(const edge& t)const{
        return w<t.w;
    }
};
struct node{
    ll pre,to,num,w;
    bool operator <(const node&t) const{
        return w>t.w;
    }
};
vector<edge> g[N];
int k[N];
ll ans[N];
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    while(t--){
        int n,m,Q;
        cin>>n>>m>>Q;
        int i;
        for(i=1;i<=n;i++) g[i].clear();
        for(i=1;i<=m;i++){
            int a,b,c;
            cin>>a>>b>>c;
            g[a].push_back({b,c});
        }
        priority_queue<node> q;
        int mx=0;
        for(i=1;i<=Q;i++){
            cin>>k[i];
            mx=max(mx,k[i]);
        }
        int cnt=0;
        for(i=1;i<=n;i++){
            sort(g[i].begin(),g[i].end());
            if(g[i].size())
            q.push({i,g[i][0].to,0,g[i][0].w});
        }
        while(q.size()){
            auto t=q.top();
            q.pop();
            cnt++;
            ans[cnt]=t.w;
            if(cnt==mx)
                break;
            if(t.num<(int)g[t.pre].size()-1){
                q.push({t.pre,g[t.pre][t.num+1].to,t.num+1,t.w-g[t.pre][t.num].w+g[t.pre][t.num+1].w});
            }
            if((int)g[t.to].size()){
                q.push({t.to,g[t.to][0].to,0,t.w+g[t.to][0].w});
            }
        }
        for(i=1;i<=Q;i++){
            cout<<ans[k[i]]<<endl;
        }
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13686651.html