P4568 飞行路线 分层图最短路

P4568 飞行路线 分层图最短路

分层图最短路

问题模型

求最短路时,可有\(k\)次更改边权(减为0)

思路

在普通求\(Dijkstra\)基础上,\(dis[x][j]\)多开一维\(j\)以存已用了多少次机会,然后每次松弛时,做完普通松弛操作后,还要使用一次机会(如果可以),类同\(DP\)

每次普通松弛:

\[dis[to][j]=min\{dis[cur][j], dis[to][j]\} \]

如果还可以使用(\(j<k\)):

\[dis[to][j+1] = min\{dis[cur][j], dis[to][j+1]\} \]

AC Code:

#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#define MAXN 10010
#define MAXK 11
#define MIN(A,B) ((A)<(B)?(A):(B))
using namespace std;
int n,m,k,s,e;
bool vis[MAXN][MAXK];
struct edge{
    int v,w;
    edge(int v, int w):v(v),w(w){}
};
vector <edge> mp[MAXN];
struct item{
    int dis, k, v;
    item(int dis, int k, int v):dis(dis), k(k), v(v){}
    bool operator < (const item a) const{
        return dis > a.dis;
    }
};
int dis[MAXN][MAXK];
priority_queue <item> q;
void Dij(){
    memset(dis, 0x3f, sizeof(dis));
    dis[s][0]=0;
    q.push(item(0,0,s));
    while(!q.empty()){
        item cur = q.top();q.pop();
        if(vis[cur.v][cur.k]) continue;
        vis[cur.v][cur.k] = 1;
        for(register int i=0;i<mp[cur.v].size();++i){
            int v = mp[cur.v][i].v, w = mp[cur.v][i].w;
            if(cur.k<k&&!vis[v][cur.k+1]&&dis[v][cur.k+1]>dis[cur.v][cur.k]){ // 使用机会
                dis[v][cur.k+1] = dis[cur.v][cur.k];
                q.push(item(dis[v][cur.k+1], cur.k+1, v));
            }
            if(!vis[v][cur.k]&&dis[v][cur.k]>dis[cur.v][cur.k]+w){ // 普通松弛
                dis[v][cur.k] = dis[cur.v][cur.k]+w;
                q.push(item(dis[v][cur.k], cur.k, v));
            }
        }
    }
}
int main()
{
    scanf("%d %d %d %d %d", &n, &m, &k, &s, &e),s++,e++;
    for(int i=1;i<=m;++i){
        int a,b,c;
        scanf("%d %d %d", &a, &b, &c),++a,++b;
        mp[a].push_back(edge(b,c));
        mp[b].push_back(edge(a,c));
    }
    Dij();
    int ans=0x3ffffff;
    for(int i=0;i<=k;++i)
        ans = MIN(ans, dis[e][i]); // 遍历统计答案,机会不一定用完
    printf("%d", ans);
    return 0;
}
posted @ 2019-05-02 20:26  Santiego  阅读(171)  评论(0编辑  收藏  举报