BZOJ2763 [JLOI2011]飛行路線(分層最短路,dijkstra的堆優化)

Description

Alice和Bob現在要乘飛機旅行,他們選擇了一家相對便宜的航空公司。該航空公司一共在n個城市設有業務,設這些城市分別標記爲0到n-1,一共有m種航線,每種航線連接兩個城市,並且航線有一定的價格。Alice和Bob現在要從一個城市沿着航線到達另一個城市,途中可以進行轉機。航空公司對他們這次旅行也推出優惠,他們可以免費在最多k種航線上搭乘飛機。那麼Alice和Bob這次出行最少花費多少?

Input

數據的第一行有三個整數,n,m,k,分別表示城市數,航線數和免費乘坐次數。

第二行有兩個整數,s,t,分別表示他們出行的起點城市編號和終點城市編號。(0<=s,t

Output

只有一行,包含一個整數,爲最少花費。

Sample Input

5 6 1
0 4
0 1 5
1 2 5
2 3 5
3 4 5
2 3 3
0 2 100

Sample Output

8

HINT

對於30%的數據,2<=n<=50,1<=m<=300,k=0;

對於50%的數據,2<=n<=600,1<=m<=6000,0<=k<=1;

對於100%的數據,2<=n<=10000,1<=m<=50000,0<=k<=10.

思路

分層圖最短路的模板題,此題洛谷上卡SPFA,所以用堆優化的dijkstra來做.

題意就是,給出你一張無向圖,你有k次機會使得某一條邊的花費爲0,求最小花費.

我們需要利用類似動態規劃的思想來進行轉移。

我們定義:

  • dis[i][j] :從起點sti點,使用了j次優惠機會所使用的最小花費.
  • vis[i][j] :從起點sti點,使用了j次優惠機會這個狀態有沒有被標記

我們需要對普通的迪傑斯特拉轉移的時候進行一些改變:

  1. 不使用免費機會的時候:

    如果 到點u的花費dis[u][k]+從u到v的邊權w<到v的邊權dis[v][k]
    正常轉移更新:dis[v][k]=dis[u][k]+w
    加入堆q.push(node(v,k,dis[v][k]))
  2. 使用免費機會的時候:

    如果 到點u的時候使用了k次機會的花費dis[u][k]<到v點的時候使用了k+1次機會的邊權dis[v][k+1]
    這條邊免費更新dis[v][k+1]=dis[u][k]
    加入堆q.push(node(v,k+1,dis[v+1][k]))

剩下的就是迪傑斯特拉的堆優化模板了。

代碼

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m, k;
int first[N], tot;

struct edge
{
    int v, w, next;
} e[N * 2];
void add_edge(int u, int v, int w)
{
    e[tot].v = v, e[tot].w = w;
    e[tot].next = first[u];
    first[u] = tot++;
}
struct node
{
    int id, now, k;
    node() {}
    node(int _id, int _k, int _now)
    {
        id = _id, now = _now, k = _k;
    }
    bool friend operator<(node a, node b)
    {
        return a.now > b.now;
    }
};
/*
dis[i][j]:表示從st到i點用了j次免費機會的最小花費
vis[i][j]:表示從st到i點用了j次免費機會有沒有被標記過
*/
int dis[N][12], vis[N][12];
void dijkstra(int st)
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j <= k; j++)
        {
            dis[i][j] = inf;
            vis[i][j] = 0;
        }
    }
    dis[st][0] = 0;
    priority_queue<node> q;
    q.push(node(st, 0, 0));
    while (!q.empty())
    {
        node u = q.top();
        q.pop();
        if (!vis[u.id][u.k])
        {
            vis[u.id][u.k] = 1;
            for (int i = first[u.id]; ~i; i = e[i].next)
            {
                int v = e[i].v, w = e[i].w;
                if (!vis[v][u.k] && dis[u.id][u.k] + w < dis[v][u.k])
                {
                    dis[v][u.k] = dis[u.id][u.k] + w;
                    q.push(node(v, u.k, dis[v][u.k]));
                }
                if (u.k < k && !vis[v][u.k + 1] && dis[u.id][u.k] < dis[v][u.k + 1])
                {
                    dis[v][u.k + 1] = dis[u.id][u.k];
                    q.push(node(v, u.k + 1, dis[v][u.k + 1]));
                }
            }
        }
    }
}
void init()
{
    mem(first, -1);
    tot = 0;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    int u, v, w, st, ed;
    scanf("%d%d%d%d%d", &n, &m, &k, &st, &ed);
    st++, ed++;
    init();
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &u, &v, &w);
        u++, v++;
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    dijkstra(st);
    int ans = inf;
    for (int i = 0; i <= k; i++)
        ans = min(ans, dis[ed][i]);
    printf("%d\n", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章