HDU 1535 Invitation Cards【Dijkstra的队列优化】

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

题意:(不知道那个时间是用来干嘛的,想了挺久的,然而可以不用理XD) 从点1开始出发把学生送到各个车站,然后在从各个车站返回到1这个位置,要求花费最短;

思路:

题目的意思就是说,从1开始到各个点之间的最短距离加上各个点到1的最短距离的总和;如果没有时间限制的话就很好求,但是节点和边都是1的6次方,数据范围非常大,这里看点和边的范围就大概可以猜到,绝对不能用点来求最短距离,应该用边,在3种求最短路得算法中,只有1个是用边来求得,就是Dijkstra的队列优化,算法的时间复杂度就是  E,非常快,如果用Bellman的话,即使是用队列优化过的,最坏的情况也是VM(V是节点,M是边),超时的可能性还是很大的;但是,按照一般的思维的话,求多点到单点的最短路,用Dijkstra的话,要重复使用V次,毕竟Dijkstra是求单源点出发的最短路的;就这一部分要多花点时间去思考;1到各点的最短距离就不说了,说说怎么求多点到单点的最短路的距离;因为不是任意两点的最短路,所以还是存在一个突破口的,就是要求的各点的终点是相同的,大家可以以题目的样例2画出一张有向图出来,然后把方向全部反过来指,会发现,各点到1的最短距离,其实就是把有向图方向反过来过后再求一次单源点到各点之间的距离;下面给出代码;

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<iostream>

using namespace std;

const int Maxn = 1e6+10;
const int Maxm = 1e6+10;
const int INF = 0x3f3f3f3f;

struct Edge {
    int u,v,w;
    Edge (int from, int to, int d):u(from),v(to),w(d) {}
};

struct Node {
    int to,d;
    Node (int v, int w):to(v),d(w) {}
    bool operator < (const Node &a1) const {
        return d > a1.d;
    }
};

struct Dijkstra {
    int n,m;
    bool vis[Maxn];
    vector<Edge> edges;
    vector<int> G[Maxn];
    int d[Maxn];

    void init (int n) {
        this->n = n;
        edges.clear();
        for (int i = 1; i <= n; ++i) G[i].clear();
    }

    void getG (int u,int v,int w) {  // vector 实现的邻接表
        edges.push_back(Edge (u,v,w));
        m = edges.size();
        G[u].push_back(m-1);
    }

    void changeG () {  // 方向全部反向 ,u,v变成v,u;
        for (int i = 1; i <= n; ++i) G[i].clear();
        for (int i = 0; i < edges.size(); ++i) {
            Edge &e = edges[i];
            G[e.v].push_back(i);
        }
    }

    void solve (int order) {
        for (int i = 1; i <= n; ++i) d[i] = INF;
        d[1] = 0;
        memset(vis,0,sizeof(vis));
        priority_queue<Node> qu;
        qu.push(Node(1,0));
        int u,from,to;
        while (!qu.empty()) {
            Node x = qu.top(); qu.pop();
            u = x.to;
            if(vis[u]) continue;
            vis[u] = 1;
            for (int i = 0; i < G[u].size(); ++i) {
                Edge & e = edges[G[u][i]];
                from = order ? e.v : e.u; // order == 1 就是反向的,0就是正向的
                to = order ? e.u : e.v;
                if(d[from] != INF && d[to] > d[from]+e.w) {
                    d[to] = d[from]+e.w;
                    qu.push(Node(to,d[to]));
                }
            }
        }

    }
} D;

int main (void)
{
    int t,V,M,u,v,w;
    scanf("%d",&t);
    for (int cas = 1; cas <= t; ++ cas) {
        scanf("%d%d",&V,&M);
        D.init (V);
        for (int i = 1; i <= M; ++i) {
            scanf("%d%d%d",&u,&v,&w);
            D.getG(u,v,w);
        }
        long long ans = 0;
        D.solve (0);
        for (int i = 2; i <= V; ++i) {
            ans+=D.d[i];
        }
        D.changeG();
        D.solve (1);
        for (int i = 2; i <= V; ++i) {
            ans+=D.d[i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81569668