当前位置: 首页 > news >正文

Dijkstra和多层图 0

众所周知,Dijkstra经常拿来解决不带负权和环的单元最短路。我们先来看一下他的实现过程

(由于朴素版用的不多,我们直接上堆优化)

模板

#include<bits/stdc++.h> 
#define mf(x,y) make_pair(x,y)//x距离,y节点 
using namespace std; 
int read(){int s=0,fl=1;char w=getchar();while(w>'9'||w<'0'){if(w=='-')fl=-1;w=getchar();}while(w<='9'&&w>='0'){s=s*10+(w^48);w=getchar();}return fl*s;
}
const int N=1000010;
int n,m,s,tot;
int head[N],ne[N],to[N],w[N];
void add(int x,int y,int ww){to[++tot]=y;ne[tot]=head[x];head[x]=tot;w[tot]=ww;  
}  
int d[N];
bool book[N];
void dj(int s){for(int i=1;i<=n;i++){d[i]=2147483647;}d[s]=0;priority_queue<pair<int,int> >q;q.push(mf(0,s)); // 将源点及其距离为0的信息加入队列  while(!q.empty()){  int x=q.top().second;q.pop(); // 取出距离最小的节点  if(book[x]){continue; // 如果节点已被访问过,则跳过 }book[x]=1; // 标记节点为已访问  for(int i=head[x];i;i=ne[i]){ // 遍历当前节点的所有邻接节点  int y=to[i]; // 邻接节点的编号if(d[y]>w[i]+d[x]){ // 如果通过当前节点可以找到更短的路径  d[y]=d[x]+w[i]; // 更新最短路径长度  q.push(mf(-d[y],y)); // 将邻接节点及其新的距离(取反后)加入队列  }}}
}
int main(){  n=read(),m=read(),s=read();for(int i=1,u,v,ww;i<=m;i++){u=read(),v=read(),ww=read();add(u,v,ww);}dj(s);for(int i=1;i<=n;i++){printf("%d ",d[i]);}cout<<endl;return 0; 
}

题目1  P4568 [JLOI2011] 飞行路线 - 洛谷

据题目可知,就是把每个城市看作一个节点,每条航线为一个边,机票费用为边权。要求在k此免费(也就是直接去一个城市而不用给机票费用)的情况下,从s飞到t

先考虑免费这个东西怎么处理。免费我们可以看作从节点1到节点2的边权为0。简单来说,我们可以建立层图

可以把这个多层图想象成「多层停车场」,每一层对应一个「权限使用次数」,帮你理解这段代码的作用:

  • 假设你要从起点开车到终点,停车场有 k+1 层(编号 0 到 k),每层对应 “使用了 j 次免费通行权限” 的状态(比如 j=0 表示一次没用到,j=1 表示用了 1 次,最多用到 j=k 次)。
  • 原始道路:每一层内部有普通道路,走一次要花 c 元(对应代码里同层边的权重 c)。
  • 免费通道:层与层之间有 “免费电梯”,从第 j 层到第 j+1 层可以免费换乘(对应跨层边的权重 0),但每次换乘会消耗一次免费次数(所以最多到第 k 层)。

来看建图的代码:

int main(){n=read();m=read();k=read();s=read();t=read();for(int i=1;i<=m;i++){int a,b,c;a=read();b=read();c=read();for(int j=0;j<=k;j++){add(a+j*n,b+j*n,c);add(b+j*n,a+j*n,c);if(j<k){add(a+j*n,b+(j+1)*n,0);add(b+j*n,a+(j+1)*n,0);}}}

a为起点,b为终点,c为权值。内层的for循环建立了k层图,也就是有多少免费次数就建多少层。因为第i层对应的是使用i次免费特权时图。

if嵌套外面的语句负责建立最基础的联通关系,提供基础信息

当j<k,代表免费次数没有用完,那么就在第j*n层和下一层建立一条边权为0的边,也就是当前层的每一个点都有免费通行到下一层的权利。

Dijkstra部分

当我们建完多层图后,就可以直接跑dijkstra了

void dj(int s){memset(d,0x7f,sizeof(d));d[s]=0;priority_queue<pair<int,int> >q;q.push(mf(0,s));while(!q.empty()){  int x=q.top().second;int p=q.top().first;q.pop();if (p>d[x]) continue;if(book[x]){continue;}book[x]=1;for(int i=head[x];i;i=ne[i]){  int y=to[i];if(d[y]>w[i]+d[x]){  d[y]=d[x]+w[i];q.push(mf(-d[y],y)); }}}
}

没啥可说的

AC代码

#include<bits/stdc++.h>
#define mf(x,y) make_pair(x,y)//x距离,y节点 using namespace std;
const int N=5000100;
int read(){int s=0,fl=1;char w=getchar();while(w>'9'||w<'0'){if(w=='-')fl=-1;w=getchar();}while(w<='9'&&w>='0'){s=s*10+(w^48);w=getchar();}return fl*s;
}
void out(int x){if(x<0)putchar('-'),x=-x;if(x<10)putchar(x+'0');else out(x/10),putchar(x%10+'0');
}
int n,m,k,s,t;
int tot;
int head[N],ne[N],to[N],w[N];
void add(int x,int y,int ww){to[++tot]=y;ne[tot]=head[x];head[x]=tot;w[tot]=ww;  
}  
int d[N];
bool book[N];
void dj(int s){memset(d,0x7f,sizeof(d));d[s]=0;priority_queue<pair<int,int> >q;q.push(mf(0,s));while(!q.empty()){  int x=q.top().second;int p=q.top().first;q.pop();if (p>d[x]) continue;if(book[x]){continue;}book[x]=1;for(int i=head[x];i;i=ne[i]){  int y=to[i];if(d[y]>w[i]+d[x]){  d[y]=d[x]+w[i];q.push(mf(-d[y],y)); }}}
}int main(){n=read();m=read();k=read();s=read();t=read();for(int i=1;i<=m;i++){int a,b,c;a=read();b=read();c=read();for(int j=0;j<=k;j++){add(a+j*n,b+j*n,c);add(b+j*n,a+j*n,c);if(j<k){add(a+j*n,b+(j+1)*n,0);add(b+j*n,a+(j+1)*n,0);}}}dj(s);int ans=1e18;for(int j=0;j<=k;j++){ans=min(ans,d[t+j*n]);}out(ans);return 0;
}

题目2

P1948 [USACO08JAN] Telephone Lines S - 洛谷

OK国际惯例,先来骗个分

不错,下面进入正题

据题可知,我们的目的只是把1号和n连起来。和上一道题一样,有k此免费连的机会。于是建图其实时差不多的。

signed main(){n=read();p=read();k=read();for(int i=1;i<=p;i++){int x,y,v;x=read();y=read();v=read();for(int j=0;j<=k;j++){add(x+j*n,y+j*n,v);add(y+j*n,x+j*n,v);if(j<k){add(x+j*n,y+(j+1)*n,0);add(y+j*n,x+(j+1)*n,0);				}}}

Dijkstra部分

void dj(int s){memset(d,0x7f,sizeof(d));d[s]=0;priority_queue<pair<int,int> >q;q.push(mf(0,s));while(!q.empty()){int x=q.top().second;int p=q.top().first;q.pop();if(book[x]) continue;book[x]=1;for(int i=head[x];i;i=ne[i]){int y=to[i];int np=max(-p,w[i]);if(d[y]>np){d[y]=np;q.push(mf(-d[y],y));}}}
}

和之前一题也差不多,但是不是求最短路,而是求当前的代价和连这条电线的最大值和y节点的最小值的最小值(?)

不过做这道题一定一定要注意数组大小,当时我就是数组开小了调了半天

AC代码

#include<bits/stdc++.h>
#define mf(a,b) make_pair(a,b)
#define int long long
using namespace std;
const int N=5000010;
int read(){int s=0,fl=1;char w=getchar();while(w>'9'||w<'0'){if(w=='-')fl=-1;w=getchar();}while(w<='9'&&w>='0'){s=s*10+(w^48);w=getchar();}return fl*s;
}
void out(int x){if(x<0)putchar('-'),x=-x;if(x<10)putchar(x+'0');else out(x/10),putchar(x%10+'0');
}
int n,p,k;
int head[N],ne[N],to[N],w[N],d[N],book[N];
int tot;
void add(int x,int y,int v){to[++tot]=y;ne[tot]=head[x];head[x]=tot;w[tot]=v;
}
void dj(int s){memset(d,0x7f,sizeof(d));d[s]=0;priority_queue<pair<int,int> >q;q.push(mf(0,s));while(!q.empty()){int x=q.top().second;int p=q.top().first;q.pop();if(book[x]) continue;book[x]=1;for(int i=head[x];i;i=ne[i]){int y=to[i];int np=max(-p,w[i]);if(d[y]>np){d[y]=np;q.push(mf(-d[y],y));}}}
}
signed main(){n=read();p=read();k=read();for(int i=1;i<=p;i++){int x,y,v;x=read();y=read();v=read();for(int j=0;j<=k;j++){add(x+j*n,y+j*n,v);add(y+j*n,x+j*n,v);if(j<k){add(x+j*n,y+(j+1)*n,0);add(y+j*n,x+(j+1)*n,0);				}}}dj(1);int ans=2e9;for(int i=0;i<=k;i++){ans=min(ans,d[n+i*n]);}out(ans==2e9?-1:ans);return 0;
}

    http://www.dtcms.com/a/337339.html

    相关文章:

  • 蓝桥杯算法之搜索章 - 7
  • LeetCode 45.跳跃游戏II:贪心策略下的最少跳跃次数求解
  • 华为云服务器从注册到部署全流程指南
  • Pomian语言处理器 研发笔记(一):使用C++的正则表达式构建词法分析器
  • 零基础数据结构与算法——第七章:算法实践与工程应用-图像处理
  • LLM - MCP传输协议解读:从SSE的单向奔赴到Streamable HTTP的双向融合
  • JavaScript 原型继承与属性访问规则详解
  • ES入门教程
  • CSDN转PDF【无水印且免费!!!】
  • linux 内核 - 进程地址空间的数据结构
  • 【STM32】STM32H750 CubeMX 配置 USB CDC 虚拟串口笔记
  • 保姆级教学:使用 Jenkins 部署前端项目(2025 年最新版)
  • 基于JS实现的中国象棋AI系统:多模块协同决策与分析
  • ffmpeg编译
  • 音视频面试题集锦第 26 期
  • 计算机网络-IPv6
  • 679. 24 点游戏
  • Android Cutout(屏幕挖孔)详解
  • ubuntu 编译ffmpeg6.1 增加drawtext,libx264,libx265等
  • Leetcode 3648. Minimum Sensors to Cover Grid
  • OCR库pytesseract安装保姆级教程
  • LeetCode:无重复字符的最长子串
  • SQLite 加密与不加密性能对比与优化实践
  • Opsqueue:为重负载而生的轻量级批处理队列,已开源!
  • 视频因为264问题无法网页播放,解决方案之一:转化视频
  • 智创飞跃|2025 Google 开发者大会伴你成长精进
  • 兴趣爱好——虾哥开源小智AI机器人搭建(丐版—最低成本)ESP32开发板 MicroPython V1.0.0 Rev1
  • 嵌入式Linux学习 -- 进程和线程4
  • 三高架构杂谈
  • Ansible 自动化运维实践笔记:Jinja2 模板、LNMP+WordPress 部署与大项目管理