[BZOJ 2763] 飞行路线 ——分层图

BZOJ 2763
飞行路线

以本题讲解分层图的用法:
在解决一些图论问题的时候,如果有一些修改的操作,比如如此题中允许免费k次这样的操作,显然在一层图中跑最短路会出问题,因此我们想到一种分层图的概念

如果我们将免费k次,抽象成建立k成图,到下一层便是免费一次【边权为0】。这样再跑一遍最短路便可以解决问题

图

#include<bits/stdc++.h>
using namespace std;

#define N 10005
#define Dist p.dist
#define Node p.node
#define Free p.free
#define Layer p.free+1
#define ToNode edge[Node][i]

int dis[15][N],n,m,w,s,e,minx=INT_MAX;          //这两个二维数组第一维为层数,第二维为当层中的dis或者vis
bool vis[15][N];

struct EdgeType{
    int to,cost;
};
struct LineType{        //Dijkstra中的优先队列
    int dist,node,free;             //dist存最小距离,node节点下表,free免费次数
    bool operator < (const LineType &x) const{
        return x.dist<dist;
    }
};

vector <EdgeType> edge[N];          //采用邻接表存图
inline int Read()
{
    int num=0,f=1;
    char t=getchar();
    while (t<'0'||t>'9') f=t=='-'?-1:1,t=getchar();
    while (t>='0'&&t<='9') num=num*10+t-'0',t=getchar();
    return num*f;
}
void Dijkstra(int s)
{
    priority_queue <LineType> line;
    memset(dis,0x7f,sizeof(dis));
    dis[1][s]=0;
    line.push(LineType{0,s,0});
    while (!line.empty())               //普通dijkstra跑一边,不过加个"如果还可以免费便往下一层跑"就行了
    {
        LineType p=line.top();line.pop();vis[Layer][Node]=1;
        for (int i=0; i<edge[Node].size(); i++) if (dis[Layer][ToNode.to] >= Dist+ToNode.cost)
        {
            dis[Layer][ToNode.to]=Dist+ToNode.cost;
            if (ToNode.to==e) minx=minx>Dist+ToNode.cost?Dist+ToNode.cost:minx;
            if (!vis[Layer][ToNode.to]) line.push(LineType{Dist+ToNode.cost,ToNode.to,Free});
        }
        if (Free < w)
        {
            for (int i=0; i<edge[Node].size(); i++) if (dis[Layer+1][ToNode.to] >= Dist)
            {
                dis[Layer+1][ToNode.to]=Dist;
                if (ToNode.to==e) minx=minx>Dist?Dist:minx;
                if (!vis[Layer+1][ToNode.to]) line.push(LineType{Dist,ToNode.to,Free+1});
            }
        }
    }   
}
/*
错误记录:
1st: 完全思路混乱,dis只定了一层,即在一层里进行操作,这样明显会造成混乱,也没达到分层的效果
2nd: 同样,vis只一层,然后这样到高层判断是否访问更新的时候也会出现问题
3rd: 输出的时候是直接按照w+1层输出,而如果用不到w次,比如直接有条s--->e的边,则会在dis[2][e]=0 ,因此弄minx记录最小值 
*/ 
int main()
{
    n=Read(),m=Read(),w=Read(),s=Read(),e=Read();
    for (int i=1; i<=m; i++) 
    {
        int f=Read(),t=Read(),v=Read();
        edge[f].push_back((EdgeType){t,v});
        edge[t].push_back((EdgeType){f,v});
    }
    Dijkstra(s);
    cout << minx; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值