同余最短路&转圈背包算法学习笔记(超详细)
一、问题引入
当你想要解决一个完全背包计数问题,但是 \(M\) 的范围太大,那么你就可以使用同余最短路。
二、算法推导过程
首先对于一个完全背包计数问题,我们要知道如果 \(x\) 这个数能凑出来,那么 \(x+a_i,x+2a_i,x+3a_i,\dots\) 一定都能凑出来,所以说,我们随便找一个 \(a_i\),找到对于 \([0,a_i-1]\) 中的每个数 \(k\) 的最小的能凑出来的数并且这个数模 \(a_i\) 等于 \(k\),这个时候从最小的可以想到最短路,于是我们就有了一个大胆的想法,首先为了节省时间复杂度,把模数设定成最小的 \(a_i\),然后进行最短路,最短路的过程就是不断尝试增加其它的 \(a_i\),然后再取模,你会发现,这是对的!哦对,刚刚只是找到了对于 \([0,a_i-1]\) 中的每个数 \(k\) 的最小的能凑出来的数并且这个数模 \(a_i\) 等于 \(k\),统计的话还要统计能加多少次 \(a_i\)。
三、同余最短路模板
#include<bits/stdc++.h>
using namespace std;
const int N = ;//数据范围
int a[N];
int f[N];
int vis[N];
struct node
{
int x;
int w;
bool operator<(const node&a)const
{
return w>a.w;
}
};
signed main()
{
int n;
long long m;
scanf("%d %lld",&n,&m);
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
memset(f,0x3f,sizeof(f));
f[0] = 0;
priority_queue<node>q;
q.push({0,0});
while(q.size())
{
node x = q.top();
q.pop();
if(vis[x.x])
{
continue;
}
vis[x.x] = 1;
for(int i = 2;i<=n;i++)
{
int v = (x.x+a[i])%a[1];
if(f[v]>f[x.x]+a[i])
{
f[v] = f[x.x]+a[i];
q.push({v,f[v]});
}
}
}
long long ans = 0;
for(int i = 0;i<a[1];i++)
{
if(f[i]<=m)
{
ans+=(m-f[i])/a[1]+1;
}
}
printf("%lld",ans-1);
return 0;
}
注意:这只是一个板子,应用时请随机应变。
四、同余最短路例题
U553673 硬币问题
同余最短路模板题,代码放上供参考:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
int a[N];
long long f[N];
int vis[N];
struct node
{
int x;
int w;
bool operator<(const node&a)const
{
return w>a.w;
}
};
signed main()
{
int n;
long long m;
scanf("%d %lld",&n,&m);
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
memset(f,0x3f,sizeof(f));
f[0] = 0;
priority_queue<node>q;
q.push({0,0});
while(q.size())
{
node x = q.top();
q.pop();
if(vis[x.x])
{
continue;
}
vis[x.x] = 1;
for(int i = 2;i<=n;i++)
{
int v = (x.x+a[i])%a[1];
if(f[v]>f[x.x]+a[i])
{
f[v] = f[x.x]+a[i];
q.push({v,f[v]});
}
}
}
long long ans = 0;
for(int i = 0;i<a[1];i++)
{
if(f[i]<=m)
{
ans+=(m-f[i])/a[1]+1;
}
}
printf("%lld",ans-1);
return 0;
}
结果稀里糊涂地拿到了最优解(不要看最快的提交,因为数据很水然后我没开 long long 结果过了,所以看第二快的提交)……
P3403 跳楼机
只需要把 \(m\) 减一(因为题目是从第 \(1\) 层开始,然而我们的代码是从第 \(0\) 层),然后正常套模板就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int a[N];
long long f[N];
int vis[N];
struct node
{
int x;
long long w;
bool operator<(const node&a)const
{
return w>a.w;
}
};
signed main()
{
int n = 3;
long long m;
scanf("%lld",&m);
m--;
for(int i = 1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
memset(f,0x3f,sizeof(f));
f[0] = 0;
priority_queue<node>q;
q.push({0,0});
while(q.size())
{
node x = q.top();
q.pop();
if(vis[x.x])
{
continue;
}
vis[x.x] = 1;
for(int i = 2;i<=n;i++)
{
int v = (x.x+a[i])%a[1];
if(f[v]>f[x.x]+a[i])
{
f[v] = f[x.x]+a[i];
q.push({v,f[v]});
}
}
}
long long ans = 0;
for(int i = 0;i<a[1];i++)
{
if(f[i]<=m)
{
ans+=(m-f[i])/a[1]+1;
}
}
printf("%lld",ans);
return 0;
}
由于作者水平不行,所以只能做这些题,后面还会有更多例题,敬请期待!
转圈背包由于太难,作者理解之后再更新!
但是似乎我发现转圈背包虽然理论上比同余最短路快,但是实际上效率远不如同余最短路,特别是在大数据,这是因为迪杰斯特拉在不被卡的情况下时间复杂度比 \(O(E \log V)\) 快得多。
同余最短路&转圈背包算法学习笔记(超详细)的更多相关文章
- python多线程学习笔记(超详细)
python threading 多线程 一. Threading简介 首先看下面的没有用Threading的程序 ): s += i time.sleep( ): s += i time. ...
- maven学习笔记(超详细总结)
目录 项目管理利器--maven 第1章 maven概述 1-1 项目管理利器-maven简介 1.1.1 什么是maven 1.1.2 什么是依赖管理 1.1.3 传统项目的依赖管理 1.1.4 m ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- Miller-Rabin 与 Pollard-Rho 算法学习笔记
前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...
- 算法学习笔记(9): 中国剩余定理(CRT)以及其扩展(EXCRT)
扩展中国剩余定理 讲解扩展之前,我们先叙述一下普通的中国剩余定理 中国剩余定理 中国剩余定理通过一种非常精巧的构造求出了一个可行解 但是毕竟是构造,所以相对较复杂 \[\begin{cases} x ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- 算法学习笔记(5): 最近公共祖先(LCA)
最近公共祖先(LCA) 目录 最近公共祖先(LCA) 定义 求法 方法一:树上倍增 朴素算法 复杂度分析 方法二:dfs序与ST表 初始化与查询 复杂度分析 方法三:树链剖分 DFS序 性质 重链 重 ...
随机推荐
- Python介绍以及应用场景
Python介绍以及应用场景 Python简介 Python,作为一种解释型.面向对象的高级编程语言,自1989年圣诞节期间由荷兰计算机科学家Guido van Rossum创造以来,已经取得了举 ...
- Luogu P1930 亚瑟王的宫殿 题解 [ 蓝 ] [ 分层图最短路 ] [ 枚举 ]
亚瑟王的宫殿:比较 tricky 的图论. 图论做法 思路 因为是无向图,所以考虑一个经典 trick,把所有点到集合点的距离之和化为集合点到其他所有点的位置之和,就可以从集合点做单源最短路了. 于是 ...
- 深入浅出 Vue3:组件与模板基础全解析
一.Vue3 组件结构详解 1.1 单文件组件(SFC)架构 Vue3采用.vue单文件组件模式,一个典型组件包含三个区块: <template> <!-- 组件的HTML模板 -- ...
- 浅谈Processing中的 println() 打印输出函数[String]
简单看一下Processing中的打印输出函数println()相关用法. 部分源码学习 /** * ( begin auto-generated from println.xml ) * * Wri ...
- Vulkan环境配置 | vscode+msvc 解决方案
Vulkan环境配置 | vscode+msvc 解决方案 前言 如果作为Windows 11侠的你是一个vscode爱好者,凑巧电脑上还安装有Visual Studio,这个时候你突然想配置一个Vu ...
- [Software Note ] Fibersim-export-OffsetedMesh
输出Offseted 的Drape data 只在fibersim 导出界面打开Allow offset simulation 选项,输出的网格还是在layup surface 上: 输出的数据并未偏 ...
- 【MATLAB习题】曲柄滑块机构运动学分析
曲柄滑块机构分享 1. 机构简图 2. 实例 3. matlab code function main %输入已知数据 clear; i1=100; i2=300; e=0; hd = pi/180; ...
- 【MATLAB习题】四杆机构的运动学参数求解
1.问题描述 2. 推导过程 3. matlab代码 最新版代码 直接采用求微分的方式得到角度,角速度等数值解,速度慢,但是代码少,容易看懂(矩阵看起来真难受). 以前做的一个博客文章用的是矩阵运算求 ...
- k8s dial tcp 127.0.0.1:6443: connect: connection refused排查流程及解决思路
前言 k8s 集群中,使用 kubelet 报错,如下: The connection to the server 127.0.0.1:6443 was refused - did you speci ...
- 从Docker Machine到K8S:容器管理为啥有这么多工具?
2018-11-09 18:01 关注嘉为科技,获取运维新知 目录 1.有了Docker,为啥还需要额外容器管理工具 2.Docker三剑客 Docker Machine Docker Compo ...