分層圖 Illegal Motor

分層圖

作用

分層圖可以處理從圖中選取k條邊使其邊權變爲0,求最短路

一個很好的例子

Illegal Motor

(Motor.c/cpp/pas)

Description

    在你的強力援助下,PCY 成功完成了之前的所有任務,他覺得,現在正是出去浪的大好時光。於是,他來到高速公路上,找到一輛摩的前往幾千公里以外他心儀的那家黃燜雞米飯。
    由於 PCY 的品味異於常人,途經幾百個城市的黃燜雞米飯他都不屑一顧,他只願意前往他心中最好的那家,但是爲了一碗二十塊錢的黃燜雞米飯,他不願意花上幾千塊的路費,他希望路費盡量少。高速路上的警察叔叔被他的行爲所打動,於是在多方協調下,最多 K 條城市之間的高速收費站願意免費爲 PCY 放行(可以任意選擇)。
    顯然,PCY 已經筋疲力盡,不想再動用自己的數學天才來計算他可以花費的最小路費,因此他希望你可以幫他最後一次,他說他可以請你吃大碗的黃燜雞米飯,還可以加一瓶豆奶。
    現在給你 N 個城市(編號爲 0 … N - 1 ), M 條道路,和每條高速公路的花費 Wi ,以及題目所描述的 K。PCY 想從城市 S 到城市 T, 因爲他對 T 城市的黃燜雞米飯情有獨鍾。

Input (Prefix.in)

第一行,三個整數 N,M,K ,如題意所描述
第二行,兩個整數 S,T ,代表出發城市和目標城市編號
接下來 M 行,每行三個整數 X,Y,W ,代表 X 和 Y 城市之間的高速公路收費爲 W 元

Output (Prefix.out)

共一行,輸出一個整數,代表 PCY 最少需要花費的路費。

1.in

5 6 1
1 5
3 4 5
1 2 15
2 3 5
4 5 5
3 4 3
1 3 1005

1.out

8

2.in

4 3 1
1 4
1 2 50
2 3 30
1 4 50

2.out

0

Hint

對於 10%的數據, N <= 100,K = 0
對於 30%的數據, N <= 5,M <= 10,K <= 2
對於 100%的數據, N <= 10,M <= 50,K <= 10,Wi <= 10
內存限制 256M ,時間限制 1s

思路

借鑑Kigo的想法,分層圖就是K層平行宇宙,每一層裏有一個完整的圖,但平行宇宙之間有互相連通的蟲洞,可以從一個平行宇宙中的一個點瞬間到達下一個平行宇宙(原先x->y 邊權爲w,現在x->y’邊權爲0),然而蟲洞是單向的,你不能回到上一個平行宇宙,只能向下一個平行宇宙走;最終,每一個平行宇宙都有同樣的目的地,看到哪一個目的地最省錢


在這裏,K層分層圖說明最多有K條0邊權的路可以走,建圖後跑最短路即可


SPFA(本題不好)

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXM 5000000
using namespace std;

int s,t,n,m,k;

inline int Read(){
    int x=0;char ch=getchar();
    while(ch<'0' || ch>'9'){ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}

struct E{
    int next,to,v;
}edge[MAXM];
int head[MAXM];int edge_num;
int dis[MAXM];

void addedge(int x,int y,int z){
    edge[++edge_num].next=head[x];
    edge[edge_num].to=y;
    edge[edge_num].v=z;
    head[x]=edge_num;
}

int que[MAXM];int front,tail;
bool inque[MAXM];

void PUSH(int x){
    tail++;
    if(tail==5000000) tail=1;
    que[tail]=x;inque[x]=1;
}

int POP(){
    front++;
    if(front==5000000) front=1;
    int t=que[front];
    inque[t]=0;
    return t;
}

void SPFA(int x){
    memset(dis,0x7f,sizeof(dis));
    PUSH(x);
    dis[x]=0;
    while(front<tail){
        int fro=POP();
        int i;
        for(i=head[fro];i;i=edge[i].next){
            if(dis[edge[i].to]>dis[fro]+edge[i].v){
                dis[edge[i].to]=dis[fro]+edge[i].v;
                if(!inque[edge[i].to]){
                    PUSH(edge[i].to);
                }
            }
        }
    }
}

void solve(){
    SPFA(s);
    int i;
    int ans=0x7fffffff;
    for(i=0;i<=k;i++){
        ans=min(ans,dis[t+n*i]);
    }
    printf("%d\n",ans);
}

int main(){
    freopen("Motor.in","r",stdin);
    freopen("Motor.out","w",stdout);
    n=Read();m=Read();k=Read();s=Read();t=Read();
    int i;
    if(k==0){
        for(i=1;i<=m;i++){
            int a=Read();int b=Read();int c=Read();
            int j;
            addedge(a,b,c);
            addedge(b,a,c);
        }
        SPFA(s);
        printf("%d\n",dis[t]);
        return 0;
    }
    for(i=1;i<=m;i++){
        int a=Read();int b=Read();int c=Read();
        int j;
        for(j=0;j<=k;j++){
            addedge(a+n*j,b+n*j,c);
            addedge(b+n*j,a+n*j,c);
            if(j<k){
                addedge(a+n*j,b+n*(j+1),0);
                addedge(b+n*j,a+n*(j+1),0);
            }
        }
    }
    solve();
    return 0;
}

堆優化Dijsktra(好)(STD)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 200005;
const int maxm = 4000005;
const int inf = 0x3f3f3f3f;

void Read(int& x)
{
    char t = getchar();
    while (t < '0' || t > '9') t = getchar();
    x = 0;
    while (t >= '0' && t <= '9') {
        x = x * 10 + t - '0';
        t = getchar();
    }
}

struct Heap
{
    int place[maxn], val[maxn], idx[maxn], node_cn;

    Heap() { node_cn = 0; memset(place, 0, sizeof(place)); }

    inline void Swap(int x, int y)
    {
        swap(place[idx[x]], place[idx[y]]);
        swap(val[x], val[y]);
        swap(idx[x], idx[y]);
    }

    void adjustup(int x)
    {
        while (x > 1) {
            if (val[x] < val[x >> 1]) {
                Swap(x, x >> 1); 
                x >>= 1;
            } else {
                break;  
            }
        }
    }

    void adjustdown(int x)
    {
        int v;
        while ((x << 1) <= node_cn) {
            v = x << 1;
            if (v + 1 <= node_cn && val[v + 1] < val[v]) v = v + 1;
            if (val[x] > val[v]) {
                Swap(x, v);
                x = v;
            } else {
                break;
            }
        }
    }

    void insert(int id, int v)
    {
        if (place[id]) {
            val[place[id]] = -inf;
            adjustup(place[id]);
            val[1] = v;
            adjustdown(1);
        } else {
            node_cn ++;
            val[node_cn] = v, idx[node_cn] = id, place[id] = node_cn;
            adjustup(node_cn);      
        }

    }   

    void pop()
    {
        Swap(1, node_cn);
        node_cn --;
        adjustdown(1);
    }
};

int fst[maxn], edge_cn = 0;
int u[maxm], v[maxm], w[maxm], nxt[maxm];

void addedge(int x, int y, int _w)
{
    edge_cn ++;
    u[edge_cn] = x, v[edge_cn] = y, w[edge_cn] = _w;
    nxt[edge_cn] = fst[x];
    fst[x] = edge_cn;
}

int n, m, k, s, t;
int dis[maxn];

void input()
{
    int x, y, z;
    memset(fst, -1, sizeof(fst));
    Read(n), Read(m), Read(k);
    Read(s), Read(t);
    for (register int i = 1; i <= m; i++) {
        Read(x), Read(y), Read(z);
        for (register int j = 0; j <= k; j++) {
            addedge(x + n * j, y + n * j, z);
            addedge(y + n * j, x + n * j, z);
            if (j < k) {
                addedge(x + n * j, y + n * (j + 1), 0);
                addedge(y + n * j, x + n * (j + 1), 0);     
            }
        }
    }
}

Heap heap;
bool vis[maxn];

void Dijsktra()
{
    int cn;
    memset(dis, inf, sizeof(dis));
    dis[s] = 0;
    heap.insert(s, 0);
    while (heap.node_cn) {
        cn = heap.idx[1];
        heap.pop();
        if (vis[cn]) continue;
        vis[cn] = true;
        for (register int i = fst[cn]; i != -1; i = nxt[i]) {
            if (!vis[v[i]] && dis[v[i]] > dis[cn] + w[i]) {
                dis[v[i]] = dis[cn] + w[i];
                heap.insert(v[i], dis[v[i]]);
            }
        }
    }
}

void solve()
{
    int ans = inf;
    Dijsktra();
    for (register int i = 0; i <= k; i++) ans = min(ans, dis[t + i * n]);
    printf("%d\n", ans);
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("Motor.in", "r", stdin);
    freopen("Motor.out", "w", stdout);
    #endif

    input();
    solve();

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章