分层图最短路

分层图

分层图确实是个不难的东西我也确实是一个菜鸡...

简要介绍

分层图常在图论问题中出现可任选K条边更改边权(变为0或是原来一半等)时应用。

分层图,就是在应对这种问题时,把原图复制K层(总共K+1层)

每相邻层之间用更改边权后的边连接对应的点(代表进行一次操作)

然后就可以在这个新图中处理,得到问题的最优解

图例如下

因为连接两层的边代表的是进行了一次不可逆的边权操作,所以都是有向边

每层图内部的边就是和原图一样了

简单说明

可能有人会有疑问,把图复制K层后,空间和时间不会爆炸嘛?

虽然分层图总共有K+1层图

但因为每层都只是单纯的复制原图

所以内容都是一样的,一般没有必要新建图

我们只需要用一个二维数组表示点编号及其所在层数

例如在求最短路时,用 dis[x][k] 表示分层图中在k层的x点的最短距离

即原图中进行了k次边权操作的 x 点最短距离

这样就不需要新建图了

(如果最后还是炸了,说明正解大概不是分层图)

 

例题

题目描述

Your are given an undirect connected graph.Every edge has a cost to pass.You should choose a path from S to T and you need to pay for all the edges in your path. However, you can choose at most k edges in the graph and change their costs to zero in the beginning. Please answer the minimal total cost you need to pay.
您将获得一个无向连通图。每条边都有成本要通过。您应该选择一条从S到T的路径,并且需要为路径中的所有边付费。但是,您可以在图中选择最多k个边,并在开始时将其成本更改为零。请回答您需要支付的最低总费用。(机翻)

输入描述:

The first line contains five integers n,m,S,T,K.
For each of the following m lines, there are three integers a,b,l, meaning there is an edge that costs l between a and b.
n is the number of nodes and m is the number of edges.
第一行包含五个整数n,m,S,T,K。
对于以下m行中的每一行,有三个整数a,b,l,这意味着在a和b之间存在成本为l的边。
n是节点数,m是边数。

输出描述:

An integer meaning the minimal total cost.
一个整数表示最小总成本。

示例1

输入

3 2 1 3 1
1 2 1
2 3 2

输出

1

备注:

1≤n,m≤1e3,1≤S,T,a,b≤n,0≤k≤m,1≤l≤1e6
Multiple edges and self loops are allowed.
来源:牛客网暑期多校第四场J题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
#define M 1000100
struct node {
    int to,next,w;
}e[2*M];
typedef pair <int,int> p;
priority_queue <p,vector<p>,greater<p> > q; 
int dis[1010][1010],head[M],s,t,n,m,k=0;
int path[1010],cnt;
bool vis[1010][1010];
void add(int u,int v,int w) {
    e[k].to=v; e[k].next=head[u]; 
    e[k].w = w; head[u]=k++;
}
void dij() {
    for (int i=1;i<=n;i++) {
        for (int j=0;j<=k;j++)
            dis[i][j] = 0x7f7f7f7f;
    }
    memset(vis,0,sizeof vis);
    int now,son,x;
    dis[s][0] = 0;
    q.push(make_pair(0,s));
    while ( q.size() ) {
        now = q.top().second;
        q.pop();
        if ( now%n == 0 ) 
            x = now/n-1,now=n;
        else x=now/n,now%=n;
        if ( vis[now][x] ) continue;
        vis[now][x] = 1;
        for (int i=head[now];~i;i=e[i].next) {
            son = e[i].to;
            if ( dis[now][x]+e[i].w<dis[son][x]) {
                dis[son][x] = dis[now][x]+e[i].w;
                q.push(make_pair(dis[son][x],son+n*x));
            }
            if ( x != cnt ) {
                if ( dis[son][x+1] > dis[now][x]) {
                    dis[son][x+1] = dis[now][x];
                    q.push(make_pair(dis[son][x+1],son+x*n+n));
                }
            }
        }
    }
}
int main() {
    int a,b,c;
    memset(head,-1,sizeof head);
    scanf("%d%d%d%d%d",&n,&m,&s,&t,&cnt);
    for (int i=1;i<=m;i++) {
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
    }
    dij();
    printf("%d\n",dis[t][cnt]);
    return 0;
}
Dij堆优化+分层图

 

 
posted @ 2019-07-29 14:47  Jachin毅轩  阅读(635)  评论(0编辑  收藏  举报