2019CCPC网络赛 HDU6705 - path K短路

题意:给出n个点m条边的有向图,问图上第K短路的长度是多少(这里的路可以经过任何重复点重复边)。

解法:解法参考https://blog.csdn.net/Ratina/article/details/100066384这位大佬的。

比赛的时候也能想到用类似Dijkstra的做法用优先队列一条一条路拓展出来但是这样会MLE也没想到解决办法。后来看了题解才学会这个比较巧妙的优化办法。

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
typedef  long long LL;
int n,m,l,Max,qu[N];
LL ans[N];
struct edge{
    int x,y,z;
    bool operator < (const edge &rhs) const {
        return z<rhs.z;
    }
};
vector<edge> G[N];

struct dat{
    LL u,v,cur,dis;
    bool operator < (const dat &rhs) const {
        return dis>rhs.dis;
    }
};

priority_queue<dat> q;
void Dijkstra() {
    while (!q.empty()) q.pop();
    for (int i=1;i<=n;i++)
        if (G[i].size()) q.push((dat){G[i][0].x,G[i][0].y,0,G[i][0].z});
    int num=0;
    while (!q.empty()) {
        dat x=q.top(); q.pop();
        ans[++num]=x.dis;
        if (num>=Max) break;
        if (x.cur+1<G[x.u].size()) 
            q.push((dat){x.u,G[x.u][x.cur+1].y,x.cur+1,x.dis+G[x.u][x.cur+1].z-G[x.u][x.cur].z});
        for (int i=0;i<G[x.v].size();i++) {
            edge e=G[x.v][i];
            q.push((dat){x.v,e.y,0,x.dis+e.z});
            break;
        }    
    }    
}

int main()
{
    int T; cin>>T;
    while (T--) {
        scanf("%d%d%d",&n,&m,&l);
        for (int i=1;i<=n;i++) G[i].clear();
        for (int i=1;i<=m;i++) {
            int x,y,z; scanf("%d%d%d",&x,&y,&z);
            G[x].push_back((edge){x,y,z});
        }
        for (int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
        Max=0;
        for (int i=1;i<=l;i++) scanf("%d",&qu[i]),Max=max(Max,qu[i]);
        Dijkstra();
        for (int i=1;i<=l;i++)
            printf("%lld\n",ans[qu[i]]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/clno1/p/11420168.html