分层图 (可以选择K条路的权为0,求最短路)

分层图可以处理从图中选取k条边使其边权变为0,求最短路

 

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 最少需要花费的路费。


借鉴Kigo的想法,分层图就是K层平行宇宙,每一层里有一个完整的图,但平行宇宙之间有互相连通的虫洞,可以从一个平行宇宙中的一个点瞬间到达下一个平行宇宙(原先x->y 边权为w,现在x->y’边权为0),然而虫洞是单向的,你不能回到上一个平行宇宙,只能向下一个平行宇宙走;最终,每一个平行宇宙都有同样的目的地,看到哪一个目的地最省钱


在这里,K层分层图说明最多有K条0边权的路可以走,建图后跑最短路即可

#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;
}
不推荐

 

#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;
}
推荐:堆优化 , DJ

 



posted @ 2018-09-03 21:12  shuai_hui  阅读(685)  评论(0编辑  收藏  举报