HDU:6705-path

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6705

题意:现在有一个 n n n个节点 m m m条边的有向图,有 q q q次询问,每次询问需要你找出在这个图中第 k k k长的路径的长度。

解题心得:

  • 首先将点 u u u能到达的所有点按照长度升序排序,在寻找路径的时候用一个优先队列记录每一条路径的信息(路径长度,路径上最后一条边的两个节点 u u u v v v v v v u u u连接的第几长的路径)。优先队列按照长度小优先的顺序,刚开始将所有的边加入其中,然后从优先队列的头弹出路径,第几次弹出就是第几长的路径。
  • 若弹出的路径最后一条边的两个节点分别是 u u u v v v v v v是连接到 u u u的第 i n d e x index index位长的边,这个时候如果直接将 v v v能够到达的每一个点扩展成新的路径分别压入优先队列,这会造成弹出一个路径加入多个路径,例如菊花图的形式,这样会 M L E MLE MLE。这个时候因为之前排序有了单调性,按照单调性其实只需要扩展两条路径,分别是将 u u u改成连接到 u u u的第 i n d e x + 1 index+1 index+1条边,此时只是替换掉了 v v v,第二种是 v v v连接 v v v之后第一位边,这个时候是在边 ( u , v ) (u,v) (u,v)之后增添了一条边。这样在弹出一条边之后最多只会增加两条边,并且由于没有打乱单调性答案就是正确的。


#include 
using namespace std;
typedef long long ll;
const ll maxn = 5e5+100;

struct Edge {
     //记录每一条边
    ll va, to;

    Edge(ll Va, ll To):
        va(Va), to(To) {
     };

    bool operator < (const Edge &x) const {
     
        return va < x.va;
    }
};

struct Node {
     //记录每一条路径
    ll len, u, v, index;//分别代表路径的长度,最后两个节点u和v,以及v是u连接的第index长的边

    Node(ll Len, ll U, ll V, ll Index):
        len(Len), u(U), v(V), index(Index){
     };

    bool operator < (const Node &x) const {
     
        return len > x.len;
    }
};

vector <Edge> ve[maxn];//存放图

ll n, m, q, query[maxn];//query记录每次询问
ll ans[maxn], Max;//ans[i]代表第i长的路径的长度
priority_queue <Node> qu;

void init() {
     
    scanf("%lld%lld%lld", &n, &m, &q);
    for(ll i=0;i<=n;i++) ve[i].clear();
    for(ll i=1;i<=m;i++) {
     
        ll u, v, c; scanf("%lld%lld%lld",&u, &v, &c);
        ve[u].push_back(Edge(c, v));
    }
    for(ll i=1;i<=n;i++) sort(ve[i].begin(), ve[i].end());//这里排序保证单调性
    for(ll i=1;i<=m;i++) scanf("%lld", &query[i]);
    Max = *max_element(query+1, query+1+m);//记录最大的那个询问

    while(!qu.empty()) qu.pop();
}

void solve() {
     
    for(ll i=1;i<=n;i++) {
     
        if(!ve[i].empty()) {
     
            qu.push(Node(ve[i][0].va, i, ve[i][0].to, 0));
        }
    }

    ll tot = 0;//记录答案
    while(tot <= Max) {
     
        ans[++tot] = qu.top().len;

        Node now = qu.top();
        qu.pop();
        if(ve[now.v].size() != 0) {
     //u改为接到比v长的那个边上的节点去
            qu.push(Node(now.len + ve[now.v][0].va, now.v, ve[now.v][0].to, 0));
        }
        if(now.index != (ve[now.u].size()-1)) {
     //v连接v之后第一长的边
            qu.push(Node(now.len - ve[now.u][now.index].va + ve[now.u][now.index + 1].va,
                         now.u, ve[now.u][now.index + 1].to, now.index + 1));
        }
    }
}

int main() {
     
//    freopen("1.in.txt", "r", stdin);
    ll t; scanf("%lld", &t);
    while(t--) {
     
        init();
        solve();
        for(ll i=1;i<=m;i++) {
     
            printf("%lld\n", ans[query[i]]);
        }
    }
    return 0;
}

你可能感兴趣的:(图论-最短路,最短路)