【图论算法】分层图最短路径

分层图,很简单

举个例题https://www.luogu.com.cn/problem/P4822

所谓分层图,可能会有k种情况来改变图的边权状况等,这时可以建k层图

对于每一层中,按照第一层即初始状况去建图

然后在相邻两层中对于可能会发生变化的边的两点,或者是按照意义需要额外连接的两点之间,再建一次边

对于数据范围,开k倍大小,然后每一层即为u+(k-1)*n

当然,具体情况自己得手推确定。

那么对于例题,就是建了k层图后,对于终点n,每一层都要去比较,以得到答案

#include<cstdio>
#include<iostream>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;

inline int read(){
    int s=0;bool flag=true;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();}
    while(isdigit(ch)){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return flag?s:-s;
}

#define inf 0x3f3f3f
const int N=50+5;
const int M=2000+10;
int n,m,k,cnt,ans=inf;
int head[N*N],dis[N*N];
bool inq[N*N];
struct edge{int v,w,next;}e[(N*M)<<1];

inline void addedge(int u,int v,int w){
    e[++cnt]=(edge){v,w,head[u]};head[u]=cnt;
}

inline void spfa(){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    dis[1]=0;inq[1]=true;
    q.push(1);
    while(!q.empty()){
        int u=q.front();q.pop();
        inq[u]=false;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                if(!inq[v]){
                    inq[v]=true;
                    q.push(v);
                }
            }
        }
    }
}

signed main(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        for(int j=0;j<=k;j++){
            addedge(u+j*n,v+j*n,w);
            addedge(v+j*n,u+j*n,w);
            if(j!=k){
                addedge(u+j*n,v+(j+1)*n,w/2);
                addedge(v+j*n,u+(j+1)*n,w/2);
            }    
        }
    }
    spfa();
    for(int i=0;i<=k;i++)    ans=min(ans,dis[n+i*n]);
    cout<<ans<<endl;
    return 0;
}

再放一个题https://www.luogu.com.cn/problem/P4568

(这个题很气人,有两个原因,一是因为这个题卡了spfa,另一个原因是打题的那天,我们班一个大佬gxm给题作者反应这个题太简单,然后紫题减1,蓝题加1,淦!)

其实意思与打法都差不多,但是这个题莫名其妙有个hack点,需要把每层图的终点相连

//分层图+dij 
#include<cstdio>
#include<iostream>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;

inline int read(){
    int s=0;bool flag=true;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')flag=false;ch=getchar();}
    while(isdigit(ch)){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return flag?s:-s;
}

#define inf 0x3f3f3f
const int N=2e5+10;
const int M=5e5+10;
int n,m,k,s,t,cnt,ans=inf;
int head[N<<5],dis[N<<5];
bool vis[N<<5];
struct edge{int v,w,next;}e[M<<5];

inline void addedge(int u,int v,int w){
    e[++cnt]=(edge){v,w,head[u]};head[u]=cnt;
}

typedef pair<int,int>    pii;

inline void dijkstra(){
    memset(dis,inf,sizeof(dis));
    dis[s]=0;
    memset(vis,0,sizeof(vis));
    priority_queue<pii,vector<pii>,greater<pii> >q;
    q.push(make_pair(0,s));
    while(!q.empty()){
        int u=q.top().second;
        q.pop();
        if(vis[u])    continue;
        vis[u]=true;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].v;
            if(dis[v]>dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                q.push(make_pair(dis[v],v));    
            }
        }
    }
}

signed main(){
    n=read(),m=read(),k=read();
    s=read(),t=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),w=read();
        for(int j=0;j<=k;j++){
            addedge(u+j*n,v+j*n,w);
            addedge(v+j*n,u+j*n,w);
            if(j<k){
                addedge(u+j*n,v+(j+1)*n,0);
                addedge(v+j*n,u+(j+1)*n,0);
            }    
        }
    }
    for(int i=1;i<=k;i++)    addedge(t+(i-1)*n,t+i*n,0); 
    dijkstra();
    cout<<dis[t+k*n]<<endl;
    return 0;
}

 

posted @ 2020-04-19 15:25  初学者Ming  阅读(609)  评论(0编辑  收藏  举报