1. 程式人生 > 實用技巧 >HDU - 6705 path (求圖上不固定起終點的第k短路)

HDU - 6705 path (求圖上不固定起終點的第k短路)

path hdu-6705

題意:給你一幅有向圖,給你q個數k ,問你在這幅圖上第k短的路徑有多長。
思路:首先有q個詢問,且沒有出現修改操作,考慮離線處理。然後我們可以用一個vector儲存所有的邊。並把每個節點的出邊按從小到大排序。接下來求出所有詢問的最大值maxk,然後我們只要求第1~maxk的短路即可。然後先把所有邊都存入一個set,並且這個set是按照路徑長短排序的。接下來保證這個set裡的元素有maxk個,然後用類似於Djikstra求最短路的方法不斷去set中的內容即可,第i次從set的頭部彈出的就是第i短路。
程式碼:

const int maxn=5e5+5;
ll ans[maxn];
int n,m,k,cur[maxn],cnt=0;
struct node{
    int v;ll w;
    node (int v = 0, int w = 0): v(v), w(w) {}
    bool operator < (const node &b) const {
        return w<b.w;
    }
};
vector<node>G[maxn];
struct Edge{
    int u,v;
    ll w;
    int id;
    Edge(int u = 0, int v = 0, ll w = 0, int id = 0): u(u), v(v), w(w), id(id) {}
    bool operator <(const Edge &b)const{
        if(w==b.w){
            if(u==b.u){
                if(v==b.v){
                    return id<b.id;
                }else{
                    return v<b.v;
                }
            }else{
                return u<b.u;
            }
        }else{
            return w<b.w;
        }
    }
    bool operator == (const Edge &b) const {
        return w == b.w && u == b.u && v == b.v && id == b.id;
    }

};
int main()
{
    int T;
    cin>>T;
    while(T--){
        scanf("%d %d %d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            G[i].clear();
        }
        set<Edge>st;
        st.clear();
        cnt=0;
        for(int i=1;i<=m;i++){
            int u,v;
            ll w;
            scanf("%d%d%lld",&u,&v,&w);
            G[u].push_back(node(v,w));
            st.insert(Edge(u,v,w,++cnt));
        }
        for(int i=1;i<=n;i++){
            sort(G[i].begin(),G[i].end());
        }
        int maxk=0;
        for(int i=1;i<=k;i++){
            scanf("%d",&cur[i]);
            maxk=max(maxk,cur[i]);
        }
        while(st.size()>maxk){
            st.erase(st.end());
        }
        for(int i=1;i<=maxk;i++){
            Edge now=*st.begin();
            st.erase(st.begin());
            ans[i]=now.w;
            if(i==maxk)break;
            int u=now.v;
            for(int j=0;j<G[u].size();j++){
                int v=G[u][j].v;
                ll w=G[u][j].w;
                if(st.size()+i<maxk){
                    st.insert(Edge(u,v,now.w+w,++cnt));
                }else{
                    set<Edge>::iterator it = st.end();
                    it--;
                    Edge last=*it;
                    if(last.w>w+now.w){
                        st.erase(it);
                        st.insert(Edge(u,v,w+now.w,++cnt));
                    }else{
                        break;
                    }
                }
            }

        }
        for(int i=1;i<=k;i++){
            printf("%lld\n",ans[cur[i]]);
        }
    }
    return 0;
}