HDU6705.Path(任意起点终点的k短路)

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

题目大意:

给你一个有向图,任意一个点和边都可以经过很多次,问你整个图中,任意起点终点的k短路的长度是多少?你需要回答q个询问,每个询问给一个k

思路:

优先队列优化搜索,每次将所有点都加入队列中,意即每个点都可以为起点。那么,如果我们真正暴力地去搜索整个图,也就是每搜到一个点就把它所有相邻的点都加入优先队列中,那很明显会喜提TLE,只要将图变得很稠密,算法就会变为O(n^2)的规模。

这里有一个比较好想的优化,对每个点出度的边按照权值从小到大排序,如果我们每次按照最小的边扩张,那就是求最短路的方式。

那么k短路的情况有哪些呢?假设当前遍历的边为e,之前的点为e.from,现在的点为e.to,那么有两种情况可能更新答案:

第一,从e.from这个点出发,不经过e,而是通过from的另一条出边,这样有可能更新答案。

第二,从e.from出发,经过了e,到达了点e.to,选择e.to的一条出边,这样有可能更新答案。

所以,对于访问的一个点,只会有一条边进入优先队列中,再暴力地找就可以实现log的复杂度了。

在具体实现的时候,优先队列维护条边当前的出点,和这条边的编号,这样可以更方便的更新答案。

#pragma GCC optimize ("O2")
#include 

using namespace std;

typedef long long ll;
typedef pair pii;
typedef pair pli;
const int MAXV=5e4+5,MAXE=5e4+5;
int V,E,Q;
ll ans[MAXV];
pii query[MAXV];

namespace G
{
    struct Edge
    {
        int to, last, l;
        void set(int _to, int _last, int _l) { to = _to, last = _last, l = _l; }
    } es[MAXE]; // 边记得开两倍!!!

    int top, head[MAXV];

    void init() { top = 0, fill(head + 1, head + V + 1, -1); }
    inline void add(int fr, int to, int l)
    {
        es[top].set(to, head[fr], l);
        head[fr] = top++;
    }
    void sort_edge()
    {
        priority_queue,greater > q;
        for(int i=1;i<=V;++i)
        {
            for(int j=head[i];~j;j=es[j].last) q.push(pii(es[j].l,es[j].to));
            for(int j=head[i];~j;j=es[j].last) tie(es[j].l,es[j].to)=q.top(),q.pop();
        }
    }
    void work()
    {
        priority_queue,greater> q;
        for(int i=1;i<=V;++i)
            if(~head[i]) q.push(pli(es[head[i]].l,head[i]));
        int pos1=0,pos2=0,cur,last;
        ll dis;
        while(pos2

 

你可能感兴趣的:(图论)