最短路算法——差分约束

差分约束

(1) 求不等式组的可行解

  • 源点:从源点出发,一定可以走到所有的边
  • 求可行解步骤:
    • 先将每个不等式 x i ≤ x j + c x_i \le x_j + c xixj+c,转化成一条从 s j s_j sj走到 s i s_i si,长度为 c k c_k ck 的一条边
    • 找一个超级源点,使得该源点一定可以遍历到所有边
    • 从源点求一遍单源最短路
      • 结果一:如果存在负环,则原不等式组一定无解
      • 结果二:如果没有负环,则 d i s t [ i ] dist[i] dist[i]就是原不等式组的一个可行解

(2) 如何求最大值或最小值

  • 结论: 如果求的是最小值,则应该求最长路;如果求的是最大值,则应该求最短路;
  • 问题1:如何转化 x i ≤ c x_i \le c xic,其中c是一个常数
    • 方法:建立一个超级源点,0,然后建立0->i,长度是c的边即可。
    • 以求 x i x_i xi的最大值为例:求所有从 x i x_i xi出发,构成的不等式链 x i ≤ x j + c j ≤ x k + c 2 + c 1 ≤ . . . ≤ c 1 + c 2 + . . . x_i \le x_j+c_j \le x_k + c_2 + c_1 \le ...\le c_1+c_2+... xixj+cjxk+c2+c1...c1+c2+...所计算出的上界(而这个上界要让所有关系都成立,那么就必须以最小的上界为上界,因此需要用最短路算法求到i这个点的最短距离)

(3) 关系:

每一个差分约束的问题都可以转换成最短路的问题

理论理解

题单

1. 糖果

第一眼:

  • 感觉和floyd的排序那一道题有点相似之处,两个点之间都有关系(ps:关系闭包)
  • 排序不一样的地方在于,这道题确定小朋友各种胡搅蛮缠的糖多糖少要求后,老师需要准备的糖个数的最小值

思考:

  • 怎么去结合这两种题目要求呢,一开始能想到的处理就是先处理关系闭包问题,同时用一个ans去记录老师需要准备的糖的数量从最少的1个开始,关系环到一个一个往后的大于关系也只是加1(这个时候又想到记录方案数那题),如果是相等的关系,当前节点的方案数是前一点的一倍,如果大于关系,当前节点的方案数等于前个节点加一,最后老师需要准备糖果的个数就是总的方案数,该觉还是可以spfa走一波,开一个cnt数组那样子
    • 这样要怎么考虑所有关系呢

听y说:

  • 二刷视频
    • 我悟了。就是这题它并没有直接给出我需要给某个小朋友多少糖,只给出了每个小朋友糖的相对数量关系,而我们需要一个超级源点,去遍历到所有的边。
    • 关于求最小值用最长路建边并做spfa求最长路,
#include<bits/stdc++.h>using namespace std;
#define int long long
int n,k;
const int N=1e5+10,M=3*N;
int h[N],e[M],ne[M],w[M],idx;
int d[N],q[N],st[N],cnt[N];void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}bool spfa(){memset(d,-0x3f,sizeof d);d[0]=0;int hh=0,tt=1;q[hh]=0;while(hh!=tt){int t=q[--tt];if(tt==N) tt=0;st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]<d[t]+w[i]){d[j]=d[t]+w[i];cnt[j]=cnt[t]+1;if(cnt[j]>=n+1) return 0;if(!st[j]){st[j]=1;q[tt++]=j;if(tt==N)tt=0;}}}}return 1;
}signed main(){scanf("%lld%lld",&n,&k);memset(h,-1,sizeof h);for(int i=0;i<k;i++){int x,a,b;scanf("%lld%lld%lld",&x,&a,&b);if(x==1) add(b,a,0),add(a,b,0);else if(x==2) add(a,b,1);else if(x==3) add(b,a,0);else if(x==4) add(b,a,1);else if(x==5) add(a,b,0);}for(int i=1;i<=n;i++) add(0,i,1);int res=spfa();if(!res){puts("-1");}else{res=0;for(int i=1;i<=n;i++) res+=d[i];printf("%lld",res);}return 0;
}

先进先出的栈

image-20240706165814290

2. 区间

第一眼:

  • 如果要让Z包含的数尽可能少,那就让一个区间的数集中在和其他区间相交的部分就可以贪心的解决这个问题了吧

听y说:

  • 用差分约束的思想做很牛逼,同时利用前缀和的思想,绝绝子
  • 两个端点约束关系:
    • s [ i ] ≥ s [ i − 1 ] s[i] \ge s[i-1] s[i]s[i1]
    • $s[i]-s[i-1] \le 1 $
    • [ a , b ] [a,b] [a,b] s [ b ] − s [ a − 1 ] ≥ c s[b]-s[a-1] \ge c s[b]s[a1]c
  • 转换成最短路模型——求最长路
    • s [ i ] ≥ s [ i − 1 ] s[i] \ge s[i-1] s[i]s[i1]
    • s [ i − 1 ] ≥ s [ i ] − 1 s[i-1] \ge s[i] -1 s[i1]s[i]1
    • s [ b ] ≥ s [ a − 1 ] + c s[b] \ge s[a-1]+c s[b]s[a1]+c
  • 接着就是模版框框的打了
#include<bits/stdc++.h>using namespace std;
//关于这里的N和M的取值,因为M代表边数,我们以最大值N建边
//最多会建3*N条边,如果也算上第N个点的位置的话,会数组越界,可以开大一个数量级
//因为并没有特别熟练空间复杂度以及并不料想到后他数据怎么卡,就开大一个数量级过了
const int N=5e4+10,M=4*N+10;
int m;
int h[N],e[M],w[M],ne[M],idx;
int d[N],st[N],cnt[N],q[N];void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;  
}bool spfa(){memset(d,-0x3f,sizeof d);d[0]=0;int hh=0,tt=1;while(hh!=tt){int t=q[hh++];if(hh==N) hh=0;st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]<d[t]+w[i]){d[j]=d[t]+w[i];if(!st[j]){st[j]=1;q[tt++]=j;if(tt==N) tt=0;}}}}}signed main(){scanf("%d",&m);memset(h,-1,sizeof h);for(int i=1;i<N;i++){add(i-1,i,0);add(i,i-1,-1);}while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);a++,b++;add(a-1,b,c);}spfa();printf("%d",d[50001]);return 0;
}
3. 排队布局

第一眼:

  • 又是usaco的牛,好多事的牛
    • 1和n之间可以任意大,说明1或n都没有能够约束他们的其他牛
    • 不存在满足要求,是不是两头牛之间的约束关系会存在矛盾

思考:

  • 学差分约束的时候时把这道题和糖果(第一题)进行着对比来学的

    • 糖果——求最小值——求最长路
    • 本题——求最大值
  • 索性先自己思考并落实一遍

    • 两头牛之间距离差分约束关系
      • 原本编号的先后顺序: s [ i ] < = s [ i + 1 ] s[i]<=s[i+1] s[i]<=s[i+1]
      • M L M_L ML条边: s [ a ] − s [ b ] ≤ c s[a]-s[b] \le c s[a]s[b]c
      • M D M_D MD条边: s [ a ] − s [ b ] ≥ c s[a]-s[b] \ge c s[a]s[b]c
    • 最短路;
      • s [ i ] < = s [ i + 1 ] s[i]<=s[i+1] s[i]<=s[i+1]
      • s [ a ] ≤ s [ b ] + c s[a] \le s[b]+c s[a]s[b]+c
      • s [ b ] ≤ s [ a ] − c s[b] \le s[a]-c s[b]s[a]c
    • Tips:
  • 为什么n一定能到其他所有边?

    • 因为第一条约束关系
  • 隐含的前缀和思想

#include<bits/stdc++.h>using namespace std;
//需要思考怎么建边,约束条件如何化成边
const int N=1e3+10,M=2e4+10+2*N,INF=0x3f3f3f3f;
int n,l,d;
int h[N],e[M],w[M],ne[M],idx;
int dist[N],st[N],cnt[N],q[N];void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}int spfa(int s){memset(dist,0x3f,sizeof dist);memset(st,0,sizeof st);memset(cnt,0,sizeof cnt);dist[s]=0;int hh=0,tt=1;q[hh]=s;while(hh!=tt){int t=q[hh++];if(hh==N) hh=0;st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i]; if(dist[j]>dist[t]+w[i]){dist[j]=dist[t]+w[i];cnt[j]=cnt[t]+1;if(cnt[j]>=n+1) return -1;if(!st[j]){st[j]=1;q[tt++]=j;if(tt==N) tt=0;}}}}return 1;
}signed main(){cin>>n>>l>>d;memset(h,-1,sizeof h);for(int i=1;i<n;i++){add(i+1,i,0);add(0,i,0);}add(0,n,0);for(int i=0;i<l;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);if(a>b) swap(a,b);add(a,b,c);}for(int i=0;i<d;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);if(a>b) swap(a,b);add(b,a,-c);}int res=spfa(0);if(res==-1) puts("-1");else{spfa(1);printf("%d",dist[n]==INF?-2:dist[n]);}return 0;
}

image-20240706170654003

4. 雇佣收银员

第一眼:

  • 感觉和区间会很像,一个时间段如果需要很多营业员,那么就让每个营业员的工作时间尽可能覆盖到这个区间
  • 输入处理比较麻烦(第二眼,实际上还好,就是变量表示需要思考一下

思考:

建边操作:

  • 用区间表示所需,采用前缀和来建立关系:

    • 某一时刻的营收员人数要大于等于这一时刻所需要的营收员人数

    • 上岗人数不能超过申请人数

  • 以时刻作为点

  • i时刻所需,i时刻申请,像是隐含的关系,就是一个人工作时长导致的区间内申请人数的变化仍然需要满足能够在某时刻大于等于所需的人数

  • 然后是某一时刻的申请人数也可以用前缀和来表示,于是可以x[i]的建边也可以用 s u m [ i ] − s u m [ i − 1 ] sum[i]-sum[i-1] sum[i]sum[i1]来表示

  • s u m [ i ] sum[i] sum[i] x [ i ] x[i] x[i] r [ i ] r[i] r[i] n u m [ i ] num[i] num[i]

  • 上岗人数约束关系如下:

    • 某一时刻的上岗人数 : s u m [ i ] − s u m [ i − 1 ] > = 0 sum[i]-sum[i-1]>=0 sum[i]sum[i1]>=0
    • 某一时刻的上岗和申请人数之间的关系: s u m [ i ] − s u m [ i − 1 ] ≤ n u m [ i ] sum[i]-sum[i-1]\le num[i] sum[i]sum[i1]num[i]
    • 某一时刻的所在的上岗人数,
      • [ 1 , 7 ] [1,7] [1,7]: s u m [ i ] + s u m [ 24 ] − s u m [ 24 − ( 7 − i ) ] > = r [ i ] sum[i]+sum[24]-sum[24-(7-i)]>=r[i] sum[i]+sum[24]sum[24(7i)]>=r[i] s u m [ i ] + s u m [ 24 ] − s u m [ 16 + i ] > = r [ i ] sum[i]+sum[24]-sum[16+i]>=r[i] sum[i]+sum[24]sum[16+i]>=r[i]
      • [ 8 , 24 ] [8,24] [8,24]: s u m [ i ] − s u m [ i − 8 ] > = r [ i ] sum[i]-sum[i-8]>=r[i] sum[i]sum[i8]>=r[i]
  • 转换成最短路模型如下:

    • s u m [ i ] > = s [ i − 1 ] sum[i]>=s[i-1] sum[i]>=s[i1]
    • s u m [ i − 1 ] > = s u m [ i ] − n u m [ i ] sum[i-1]>=sum[i]-num[i] sum[i1]>=sum[i]num[i]
    • s u m [ i ] > = s u m [ 16 + i ] − s u m [ 24 ] + r [ i ] sum[i]>=sum[16+i]-sum[24]+r[i] sum[i]>=sum[16+i]sum[24]+r[i]
    • s u m [ i ] > = r [ i ] + s u m [ i − 8 ] sum[i]>=r[i]+sum[i-8] sum[i]>=r[i]+sum[i8]
#include<bits/stdc++.h>using namespace std;
const int N=30,M=100;
int n,sum[N],r[N],num[N];
int h[N],e[M],ne[M],w[M],idx;
int cnt[N],st[N],q[M],d[N];void add(int a,int b,int c){e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}void build(int c){memset(h,-1,sizeof h);idx=0;for(int i=1;i<=24;i++){add(i-1,i,0);add(i,i-1,-num[i]);}for(int i=1;i<=7;i++) add(16+i,i,r[i]-c);for(int i=8;i<=24;i++) add(i-8,i,r[i]);add(0,24,c),add(24,0,-c);
}bool spfa(int s24){memset(d,-0x3f,sizeof d);memset(st,0,sizeof st);memset(cnt,0,sizeof cnt);build(s24);int hh=0,tt=1;d[0]=0;q[0]=0;while(hh!=tt){int t=q[hh++];if(hh==N) hh=0;st[t]=0;for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(d[j]<d[t]+w[i]){d[j]=d[t]+w[i];cnt[j]=cnt[t]+1;if(cnt[j]>=25) return false;if(!st[j]){st[j]=1;q[tt++]=j;if(tt==N) tt=0;}}}}return true;
}signed main(){int t;cin>>t;while(t--){memset(num,0,sizeof num);for(int i=1;i<=24;i++){scanf("%d",r+i);}cin>>n;while(n--){int x;scanf("%d",&x);num[x+1]++;}int res=0;for(int i=0;i<=1000;i++){//res=spfa(i);if(spfa(i)){res=1;cout<<i<<endl;break;}}if(!res)puts("No Solution");}return 0;
}
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
4
0
8
16
16

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/371031.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面试八股文】java基础知识

引言 本文是java面试时的一些常见知识点总结归纳和一些拓展&#xff0c;笔者在学习这些内容时&#xff0c;特地整理记录下来&#xff0c;以供大家学习共勉。 一、数据类型 1.1 为什么要设计封装类&#xff0c;Integer和int区别是什么&#xff1f; 使用封装类的目的 对象化:…

C++ 引用——常量引用

作用&#xff1a;常量引用主要用来修饰形参&#xff0c;防止误操作 在函数形参列表中&#xff0c;可以加const修饰形参&#xff0c;防止形参改变实参 示例&#xff1a; 运行结果&#xff1a;

微信小程序消息通知(一次订阅)

在微信公众平台配置通知模版 通过wx.login获取code发送给后端 let that this // 登陆codewx.login({success: function (res) {if (res.code) {// 发送code到后端换取openid和session_keythat.setData({openCode: res.code})console.log(that.data.openCode, openCode);// 调…

ARMv8寄存器详解

文章目录 一、ARMv8寄存器介绍二、通用寄存器三、 PSTAE寄存器四、特殊寄存器五、系统寄存器 一、ARMv8寄存器介绍 本文我来给大家介绍一下ARMv8的寄存器部分&#xff0c;ARMv8中有34个寄存器&#xff0c;包括31个通用寄存器、一个栈指针寄存器SP(X31),一个程序计数器寄存器PC…

Git中两个开发分支merge的原理

一 分支合并 1.1 原理 分支合并&#xff1a;就是将A分支修改后且commit的内容&#xff0c;合并到B分支&#xff0c;这些修改且提交的内容和B分支对应的内容和位置进行比较&#xff1a; 1.不一样的话&#xff0c;提示冲突&#xff0c;需要人工干预。 2.一样的话&#xff0c;…

LLM - 卷积神经网络(CNN)

1. 卷积神经网络结构&#xff1a;分为输入层&#xff0c;卷积层&#xff0c;池化层&#xff0c;全连接层&#xff1b; &#xff08;1&#xff09;首先进入输入层&#xff0c;对数据数据进行处理&#xff0c;将输入数据向量化处理&#xff0c;最终形成输入矩阵。 &#xff08;…

vue3使用方式汇总

1、引入iconfont阿里图库图标&#xff1a; 1.1 进入阿里图标网站&#xff1a; iconfont阿里&#xff1a;https://www.iconfont.cn/ 1.2 添加图标&#xff1a; 1.3 下载代码&#xff1a; 1.4 在vue3中配置代码&#xff1a; 将其代码复制到src/assets/fonts/目录下&#xff1…

Overleaf :LaTeX协作神器!【送源码】

Overleaf 是一个广受欢迎的在线 LaTeX 编辑器&#xff0c;专为学术写作和文档排版设计。它以其协作功能和用户友好的界面而闻名&#xff0c;使得 LaTeX 编辑变得更加容易和直观。 软件介绍 Overleaf 提供了一个基于云的 LaTeX 编辑环境&#xff0c;支持实时协作&#xff0c;使得…

Nordic 52832作为HID 键盘连接配对电视/投影后控制没反应问题的分析和解决

问题现象&#xff1a;我们的一款HID键盘硬件一直都工作的很好&#xff0c;连接配对后使用起来和原装键盘效果差不多&#xff0c;但是后面陆续有用户反馈家里的电视等蓝牙设备配对连接我们的键盘后&#xff0c;虽然显示已连接&#xff0c;但实际上控制不了。设备涉及到了好些品牌…

Blazor SPA 的本质是什么以及服务器端渲染如何与 Blazor 的新 Web 应用程序配合使用

Blazor 通常被称为单页应用程序 (SPA) 框架。当我第一次开始使用 Blazor 时&#xff0c;我对 SPA 的含义、组件如何为 SPA 架构做出贡献以及所有这些如何与交互性联系在一起感到困惑。 今天&#xff0c;我将解答大家可能关心的三个问题&#xff1a; 什么是 SPA&#xff1f;了…

STM32 Cannot access memory

问题描述 最近自己做了一块STM32F103ZET6的板子&#xff0c;在焊接完成后可以在下载器界面看到idcode&#xff0c;但烧录时报错 Cannot access memory 。 解决办法 测量STM32各个供电项&#xff0c;发现时33脚处VDDA电压只有1.8V&#xff0c;是因为R3电阻过大&#xff0c;…

基于YOLOv9的脑肿瘤区域检测

数据集 脑肿瘤区域检测&#xff0c;我们直接采用kaggle公开数据集&#xff0c;Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好&#xff0c;数据内容如下 数据集中共包含700张图像&#xff0c;其中训练集500张&#xff0c;验证集200张 模型训…

Xilinx FPGA:vivado关于真双端口的串口传输数据的实验

一、实验内容 用一个真双端RAM&#xff0c;端口A和端口B同时向RAM里写入数据0-99&#xff0c;A端口读出单数并存入单端口RAM1中&#xff0c;B端口读出双数并存入但端口RAM2中&#xff0c;当检测到按键1到来时将RAM1中的单数读出显示到PC端&#xff0c;当检测到按键2到来时&…

YOLO V7网络实现细节(2)—网络整体架构总结

YOLO V7网络整体架构总结 YOLO v7网络架构的整体介绍 不同GPU和对应模型&#xff1a; ​​​​​​​边缘GPU&#xff1a;YOLOv7-tiny普通GPU&#xff1a;YOLOv7​​​​​​​云GPU的基本模型&#xff1a; YOLOv7-W6 激活函数&#xff1a; YOLOv7 tiny&#xff1a; leaky R…

openmetadata1.3.1 自定义连接器 开发教程

openmetadata自定义连接器开发教程 一、开发通用自定义连接器教程 官网教程链接&#xff1a; 1.https://docs.open-metadata.org/v1.3.x/connectors/custom-connectors 2.https://github.com/open-metadata/openmetadata-demo/tree/main/custom-connector &#xff08;一&…

24西安电子科技大学经济与管理学院—考研录取情况

24西安电子科技大学—经理与管理学院—考研录取统计 01、经理与管理学院各个方向 02、24经济与管理近三年复试分数线对比 1、经管院24年院线相对于23年院线普遍下降2-15分&#xff0c;个别专业上涨4-10分。 2、经管院应用经济学2024年院线350分&#xff1b;管理科学与工程院线…

Apache Seata tcc 模块源码分析

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 一 .导读 spring 模块分析中讲到&#xff0c;Seata 的 spring 模块会对涉及到分布式业务的 b…

Linux——进程间通信一(共享内存、管道、systrem V)

一、进程间通信介绍 1.1、进程间通信的概念和意义 进程间通信(IPC interprocess communication)是一组编程接口&#xff0c;让不同进程之间相互传递、交换信息(让不同的进程看到同一份资源) 数据传输:一个进程需要将它的数据发送给另外一个进程 资源共享:多个进程之间共享同样…

如何选择一家适合自己的商城源码?

商城源码的选择取决于多个因素&#xff0c;包括商城的功能需求、稳定性、易用性、可定制性以及价格等。启山智软作为在市场上被广泛认可且表现优异的商城源码提供商&#xff0c;具有以下的特点和优势&#xff1a; 特点①&#xff1a;国内知名的B2B2C开源商城源码系统&#xff…

Golang | Leetcode Golang题解之第213题打家劫舍II

题目&#xff1a; 题解&#xff1a; func _rob(nums []int) int {first, second : nums[0], max(nums[0], nums[1])for _, v : range nums[2:] {first, second second, max(firstv, second)}return second }func rob(nums []int) int {n : len(nums)if n 1 {return nums[0]}…