2018 NanJing ICPC Online Contest L Magical Girl Haze (BZOJ - 2763) 分层最短路

Description

分层图最短路,就是在分层图上解决最短路问题。
主要是应用于变化的最短路问题,问题常表现为一个最短路问题上加一些手脚,如减小一些边权,改变一些连接,但事先又不知道,或可以自由选择改变哪个边,最终求最短路等等。由于无法知道改变了那些边,所以用到分层图思想。
1.一种解决方法是多开一维记录状态,多开的维度记录状态的种类数即为分层数
2.另一种解决方法是可以理解为平行宇宙 一样的东西 就是把原图复制出来 k k k个,然后在原图连接的基础上,在相邻层中间加一些要求的变化边,通常是单向的(保证从每一层到下一层不再回来),再跑最短路。

个人觉得第一种更好一点。第二种方法需多建很多点和边,容易 M L E MLE MLE
本题就是取自于 B Z O J 2763 BZOJ2763 BZOJ2763,不过是有向边且数据范围扩大了。
题意就是从 1 → n 1 \to n 1n的最短路径长度,其中最多可以使得 K K K条路径免费。


Input

1 ≤ T ≤ 5 1 \leq T\leq 5 1T5
N ≤ 1 0 5 N\leq 10^5 N105
M ≤ 2 ∗ 1 0 5 M\leq 2*10^5 M2105
K ≤ 10 K\leq 10 K10
0 ≤ c i ≤ 1 0 9 0 \leq c_i\leq 10^9 0ci109


Output

最短路径长度


Solution

1.一种解决方法是多开一维记录状态,多开的维度记录状态的种类数即为分层数.
d i s t [ i ] [ j ] : 表 示 到 达 i 点 的 第 j 层 最 短 路 径 。 也 可 以 说 到 达 i 点 使 用 了 j 次 免 费 路 径 的 最 短 路 径 。 dist[i][j]:表示到达i点的第j层最短路径。也可以说到达i点使用了j次免费路径的最短路径。 dist[i][j]:iji使j
答 案 就 是 d i s t [ n ] [ k ] 答案就是dist[n][k] dist[n][k]
更 新 的 时 候 除 了 对 当 前 层 的 点 松 弛 还 要 对 下 一 层 的 点 进 行 松 弛 。 更新的时候除了对当前层的点松弛还要对下一层的点进行松弛。


Codes

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
typedef long long ll;
struct Edge {
    int to;
    ll cost;
    Edge(){}
    Edge(int _t,ll _c) {to = _t;cost = _c;}
};
vector<Edge> ways[maxn];
struct qNode {
    int x,y;
    ll cost;
    qNode(){}
    qNode(int _t,int _k,ll _c) {x = _t;y = _k;cost = _c;}
    bool operator < (const qNode &a) const {
        return cost > a.cost;
    }
};
int n,m,k,from,to;
bool vis[maxn][15];
ll dist[maxn][15];
inline void init() {
    for(int i=0;i<maxn;i++) ways[i].clear();
}
inline void addedge(int u,int v,ll c) {
    ways[u].push_back(Edge(v,c));
}
ll solve(int from,int to) {
    memset(vis,0,sizeof(vis));
    memset(dist,0x3f,sizeof(dist));
    //printf("%lld\n",dist[0][0]);
    priority_queue<qNode> qu;
    while(!qu.empty()) qu.pop();
    dist[from][0] = 0;
    qu.push(qNode(from,0,dist[from][0]));
    qNode now;
    Edge tmp;
    while(!qu.empty()) {
        now = qu.top(); qu.pop();
        int u = now.x,step = now.y;
        vis[u][step] = true;
        for(int i=0;i<ways[u].size();i++) {
            tmp = ways[u][i];
            int v = tmp.to;ll cost = tmp.cost;
            if(!vis[v][step] && dist[v][step] > dist[u][step] + cost) {
                dist[v][step] = dist[u][step] + cost;
                qu.push(qNode(v,step,dist[v][step]));
            }
            /// 对下一层进行松弛
            if(step == k) continue;
            if(!vis[v][step+1] && dist[v][step+1] > dist[u][step]) {
                dist[v][step+1] = dist[u][step];
                qu.push(qNode(v,step+1,dist[v][step+1]));
            }
        }
    }
    return dist[to][k];
}
int main()
{
    int caset;scanf("%d",&caset);
    while(caset--) {
        scanf("%d%d%d",&n,&m,&k);
        init();
        // scanf("%d%d",&from,&to);
        ll c;
        for(int i=0,u,v;i<m;i++) {
            scanf("%d%d%lld",&u,&v,&c);
            addedge(u,v,c);
        }
        ll ans = solve(1,n);
        printf("%lld\n",ans);
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值