BZOJ:2763-[JLOI2011]飞行路线(最短路分层图)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2763

 


 

解题心得:

  • 第一次见到分层最短路。其实题中说选择k条路径免费,那怎么选k条路径并没有一个明确的选法,就只能遍历。分层图就是一个图分成k层,每个节点可以走当前层的相邻节点,费用为cost,但是也可以走下一层的相邻节点,费用为0,因为只有k层,所以从第0层的S到达第k层的T也就走了k个免费路径。这个时候K不能太大,不然容易MLE。

 

#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 5e5+100;
const ll INF = 1e12;

ll n, m, k, S, T;

struct edge {
    ll to, len;

    edge(ll to1, ll len1):
            to(to1), len(len1){};
};

struct NODE {//记录队列中节点的位置,层数,花费
    ll len, pos, c;

    bool friend operator < (NODE a, NODE b) {
        return a.len > b.len;
    }

    NODE (ll len1, ll pos1, ll c1):
            len(len1), pos(pos1), c(c1){};
};

vector <edge> ve[maxn];

ll dis[11][maxn];

void add_edge(ll u, ll v, ll len) {//注意是双向边
    ve[u].push_back(edge(v, len));
    ve[v].push_back(edge(u, len));
}

void init() {
    for(int i=0;i<11;i++)
        for(int j=0;j<maxn;j++)
            dis[i][j] = INF;

    scanf("%lld%lld%lld",&n,&m,&k);
    scanf("%lld%lld",&S, &T);
    for(int i=0;i<m;i++) {
        ll u, v, len;
        scanf("%lld%lld%lld",&u, &v, &len);
        add_edge(u, v, len);
    }
}

void dij() {//用dij不容易被卡网格图
    priority_queue <NODE> qu;
    qu.push(NODE(0, S, 0));
    dis[0][S] = 0;
    while(!qu.empty()) {
        NODE now = qu.top(); qu.pop();
        ll u = now.pos;
        for(int i=0;i<ve[u].size();i++) {//走当前层
            ll v = ve[u][i].to;
            ll len = ve[u][i].len;
            ll c = now.c;
            if(dis[c][v] > dis[c][u]+len) {
                dis[c][v] = dis[c][u] + len;
                qu.push(NODE(dis[c][v], v, c));
            }
        }

        ll c = now.c;
        if(c < k) {//走下一层
            for (int i = 0; i < ve[u].size(); i++) {
                ll v = ve[u][i].to;
                if(dis[c+1][v] > dis[c][u]) {//花费为0
                    dis[c+1][v] = dis[c][u];
                    qu.push(NODE(dis[c][u], v, c+1));
                }
            }
        }
    }
}

void min_path() {
    dij();
    ll Min = INF;
    for(int i=0;i<=k;i++) {
        Min = min(Min, dis[i][T]);
    }
    printf("%lld\n", Min);
}

int main() {
    init();
    min_path();
}

 

posted @ 2018-09-02 16:25  GoldenFingers  阅读(385)  评论(0编辑  收藏  举报