【P1588】丢失的牛——区间dp/bfs
(题面来自Luogu)
题目描述
FJ丢失了他的一头牛,他决定追回他的牛。已知FJ和牛在一条直线上,初始位置分别为x和y,假定牛在原地不动。FJ的行走方式很特别:他每一次可以前进一步、后退一步或者直接走到2*x的位置。计算他至少需要几步追上他的牛。
输入格式
第一行为一个整数t(≤10),表示数据组数;接下来每行包含一个两个正整数x和y(0<x,y≤10^5),分别表示FJ和牛的坐标。
输出格式
对于每组数据,输出最少步数。
这个数据范围下bfs能过实在是很玄……(你以为你的dp能胜过我的bfs吗,jojo!)
由于这题第一次扫到某点得到的就是最优解,不需要重复遍历,bfs的复杂度是O(n)的。
bfs代码:
- #include <iostream>
- #include <cstring>
- #include <queue>
- using namespace std;
- queue<int> q;
- bool vis[100010];
- int dis[100010];
- int main() {
- ios::sync_with_stdio(0);
- int t, x, y;
- cin >> t;
- while (t--) {
- cin >> x >> y;
- if (x > y) {
- cout << x - y << endl;
- continue;
- }
- while (q.size()) q.pop();
- memset(vis, 0, sizeof(vis));
- q.push(x);
- dis[x] = 0;
- vis[x] = true;
- while (!q.empty()) {
- int k = q.front();
- q.pop();
- if (k == y) {
- cout << dis[k] << endl;
- break;
- }
- for (int i = 0; i <= 2; ++i) {
- int v;
- switch (i) {
- case 0:
- v = 2 * k;
- break;
- case 1:
- v = k + 1;
- break;
- case 2:
- v = k - 1;
- }
- if (vis[v] || !v || v > 100000) continue;
- dis[v] = dis[k] + 1;
- vis[v] = true;
- q.push(v);
- }
- }
- }
- return 0;
- }
主要想谈一谈dp的做法。这题用区间dp的思路并不显然,写出来则非常优美。设f[i]表示到达点i的最短步数,边界状态f[x] = 0。容易想到,f[i]可以从如下状态递推而来:
f[i] = min(f[i - 1], f[i + 1]) + 1(i为奇数)
f[i] = min(f[i - 1], f[i + 1], f[i / 2]) + 1(i为偶数)
这就是f的状态转移方程。只要设计出转移阶段(顺序)进行转移,最终f[y]就是所求答案。这也是本题dp设计的难点,合适的顺序安排要保证用来更新f[i]的若干状态在使用时都已经达到了最优。
考虑到小于x的位置仅可能是从x倒退回来,那么我们可以先从f[x - 1]到f[1]倒着递推,有f[i] = f[i + 1] + 1。这样得到的每个f[i](i 属于 [1, x - 1])一定是最优解。同时,我们可以用每个f[i]更新一次f[2i]。接下来我们从f[x + 1]顺着递推到f[y],此时的每个点i满足f[i] = min(f[i], f[i - 1] + 1, f[i + 1] + 1)。最后一个参数比较特殊,它表示要考虑f[i + 1]之前被某个i*2更新的情况。现在每个f[i]都已经是最优解,我们同样要用f[i]来更新f[2i],为了避免特判,数组开两倍。
写到这里发现一个没有被卡掉的漏洞:由于没有拿f[x]来更新f[2x],对于y = 2x的情况程序会给出由f[2x - 1]和f[2x + 1]更新出的错误答案,因此第二个循环应当从f[x]开始递推。
dp代码:(是不是短了很多呢)
- #include <iostream>
- #include <cstring>
- using namespace std;
- int f[200100];
- int main() {
- int t, x, y;
- cin >> t;
- while (t--) {
- cin >> x >> y;
- memset(f, 0x3f, sizeof(f));
- f[x] = 0;
- for (int i = x - 1; i; --i) {
- f[i] = f[i + 1] + 1;
- f[i << 1] = min(f[i << 1], f[i] + 1);
- }
- for (int i = x; i <= y; ++i) {
- f[i] = min(f[i], min(f[i + 1] + 1, f[i - 1] + 1));
- f[i << 1] = min(f[i << 1], f[i] + 1);
- }
- cout << f[y] << endl;
- }
- return 0;
- }
【P1588】丢失的牛——区间dp/bfs的更多相关文章
- 洛谷P1588 丢失的牛
P1588 丢失的牛 158通过 654提交 题目提供者JOHNKRAM 标签USACO 难度普及/提高- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 答案下载下来是对的,但 ...
- 洛谷——P1588 丢失的牛
P1588 丢失的牛 题目描述 FJ丢失了他的一头牛,他决定追回他的牛.已知FJ和牛在一条直线上,初始位置分别为x和y,假定牛在原地不动.FJ的行走方式很特别:他每一次可以前进一步.后退一步或者直接走 ...
- 洛谷 P1588 丢失的牛
题目描述 FJ丢失了他的一头牛,他决定追回他的牛.已知FJ和牛在一条直线上,初始位置分别为x和y,假定牛在原地不动.FJ的行走方式很特别:他每一次可以前进一步.后退一步或者直接走到2*x的位置.计算他 ...
- [JZOJ]1293.气象牛[区间DP]
Description 为了研究农场的气候,Betsy帮助农夫John做了N(1 <= N <= 100)次气压测量并按顺序记录了结果M_1-M_N(1 <= M_i <= 1 ...
- 区间DP 基本题集
51 Nod 1021 石子归并 模板题,敲就完事了,注意一下这种状态转移方程有个四边形的优化(时间) #include <cstdio> #include <iostream> ...
- UVA - 1632 Alibaba (区间dp+常数优化)
题目链接 设$dp[l][r][p]$为走完区间$[l,r]$,在端点$p$时所需的最短时间($p=0$代表在左端点,$p=1$代表在右端点) 根据题意显然有状态转移方程$\left\{\begin{ ...
- 算法复习——区间dp
感觉对区间dp也不好说些什么直接照搬讲义了2333 例题: 1.引水入城(洛谷1514) 这道题先开始看不出来到底和区间dp有什么卵关系···· 首先肯定是bfs暴力判一判可以覆盖到哪些城市····无 ...
- 71: libreoj #10151 区间dp
$des$ https://loj.ac/problem/10151 $sol$ 区间dp $f_{i, j}$ 表示区间 $[l, r]$ 合并的最大值 枚举中间点 $k$ $f_{i, j} =m ...
- 浙工大新生赛莫队处理+区间DP+KMP+分析题
题目描述 读入一个长度为n的整数数列a1,a2,…,an,以及一个整数K. q组询问. 每组询问包含一个二元组(l, r), 其中1≤l≤r≤ n, 求所有满足以下条件的二元组(l2, r2)的数目: ...
随机推荐
- Memcached 的惹祸,.NET 5.0 的背锅
抱歉,拖到现在才写这篇为 .NET 5.0 洗白的博文(之前的博文),不好意思,又错了,不是洗白,是还 .NET 5.0 的清白. 抱歉,就在今天上午写这篇博客的过程中,由于一个bug被迫在访问高峰发 ...
- Yum 命令出现[Errno 256] No more mirrors to try错误的解决方式
今天我在虚拟机上安装 NetCore 的 SDK 的时候,出现错误,执行命令:"yum install dotnet-sdk-3.1",最后安装失败,很多安装包没有找到镜像.解决方 ...
- get方法和post方法的区别?
get是从服务器上获取数据,post是向服务器传送数据,会新增资源或者修改已有资源,因此get一般用于查询,psot多用新增和修改: get和post在本质上来说没有多大区别,都是tcp链接,要说最大 ...
- Express 配置HTML页面访问
Express 配置HTML页面访问 1.配置模板引擎 Express默认的模板引擎是pug(jade),想要渲染html页面必须要导入对应的模板引擎ejs npm install ejs 安装完成在 ...
- 4g工业路由器的覆盖范围分析
4G工业路由器通常覆盖范围在60-80米之间,而影响4G工业路由器的覆盖范围有以下几个因素. 影响4g工业路由器覆盖范围的因素一:环境 空旷的环境下4g工业路由器的信号覆盖范围必然更加广阔,如果传输环 ...
- mns: Money Never Sleeps! 自己开发的一款 IDEA 插件介绍.
一边敲代码, 一边关注股票/基金行情, 还不怕同事盯到自己的屏幕! 对于一个关注股市跟基金的研发人员来说, 莫过于一天到晚写代码, 而不能及时的查看股市行情跟基金走势了吧. 写代码的时候比较容易忘记看 ...
- Docker(9)- docker pull 命令详解
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 作用 从镜像仓库中拉取或更新镜像 ...
- 10万用户一年365天的登录情况如何用redis存储,并快速检索任意时间窗内的活跃用户
1.redsi的bitmap数据结构介绍 bitmap本质上是一个string类型,只是他操作的是string的某个位是0还是1. setbit和getbit 两条命令是对字符串的位操作.每个位只能是 ...
- R语言factor类型转numeric
R 语言中为了进行数据分析,比如回归分析,这时候对于数据表格中的factor类型的数据会带来弊端,比如对因子的每一个数据都进行一次回归,这样就显得很复杂,且违背了我们的初衷,需要把factor转换为n ...
- 5.MVCC
5 MVCC 全称是Multi-Version Concurrent Control,即多版本并发控制,在MVCC协议下,每个读操作会看到一个一致性的snapshot,并且可以实现非阻塞的读.MV ...