开车旅行(算法竞赛进阶指南,倍增优化 DP)

2024-03-30 13:48

本文主要是介绍开车旅行(算法竞赛进阶指南,倍增优化 DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.题目链接:

开车旅行

二.题目大意:

中文题有点长,就不误导大家了...

三.分析:

先预处理出一下量:

ga[i]:从城市 i 出发,小 A 下一步要到的城市.

gb[i]:从城市 i 出发,小 B 下一步要到的城市.

f[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后到达的城市编号.

da[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 A 走过的距离.

db[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 B 走过的距离. 

求出上述结果后,我们就可以利用倍增以 O(log_2x) 的时间复杂度求出小 A 与 小 B 分别走的距离.

下面给出上述结果的求解方法.

ga[i]:从城市 i 出发,小 A 下一步要到的城市.

gb[i]:从城市 i 出发,小 B 下一步要到的城市.

倒序枚举城市 i,二分可以找出第一个高度大于等于城市 i 的城市,左右寻找即可.

void init_g()
{set < pair <ll, int> > st;st.emplace(make_pair(inf, 0));st.emplace(make_pair(inf + 1, 0));st.emplace(make_pair(-inf, 0));st.emplace(make_pair(-inf - 1, 0));for(int i = n; i >= 1; --i){auto j = st.lower_bound(make_pair(h[i], i));--j, --j;ll mn = inf, sm = inf;int mni, smi;for(int k = 0; k < 4; ++k){auto p = *j;ll d = (ll)abs(p.first - h[i]);if(d < mn){sm = mn, smi = mni;mn = d, mni = p.second;}else if(d < sm){sm = d, smi = p.second;}++j;}ga[i] = smi, gb[i] = mni;st.emplace(make_pair(h[i], i));}
}

 

f[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后到达的城市编号.

i = 0:f[0][j][0] = ga[j], f[0][j][1] = gb[j];

i = 1:f[1][j][k] = f[0, f[0][j][0], 1 - k];

i > 1:f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];

void init_f()
{for(int j = 1; j <= n; ++j){f[0][j][0] = ga[j];f[0][j][1] = gb[j];}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[1][j][k] = f[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];}}}
}

 

 da[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 A 走过的距离.

 db[i][j][k]:从城市 j 出发,k 先走,走 2^i 步后,小 B 走过的距离. 

首先定义函数 get_dist(i, j) = abs(h[i] - h[j]);

i = 0:da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;

           db[0][j][0] = 0, db[0][j][1] = get_dist(j, gb[j]);

i = 1:da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];

          db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];

i > 1:da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];

          db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];

int get_dist(int i, int j)
{return (int)abs(h[i] - h[j]);
}void init_d()
{for(int j = 1; j <= n; ++j){da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];}}}
}

 

四.代码实现:

#include <bits/stdc++.h>
using namespace std;typedef long long ll;const int M = (int)1e5;
const int N = (int)17;
const ll inf = 0x3f3f3f3f3f3f3f3f;int n;
int h[M + 5];
int ga[M + 5], gb[M + 5];
int f[N][M + 5][2];
ll da[N][M + 5][2], db[N][M + 5][2];void read()
{scanf("%d", &n);for(int i = 1; i <= n; ++i)scanf("%d", &h[i]);
}void init_g()
{set < pair <ll, int> > st;st.emplace(make_pair(inf, 0));st.emplace(make_pair(inf + 1, 0));st.emplace(make_pair(-inf, 0));st.emplace(make_pair(-inf - 1, 0));for(int i = n; i >= 1; --i){auto j = st.lower_bound(make_pair(h[i], i));--j, --j;ll mn = inf, sm = inf;int mni, smi;for(int k = 0; k < 4; ++k){auto p = *j;ll d = (ll)abs(p.first - h[i]);if(d < mn){sm = mn, smi = mni;mn = d, mni = p.second;}else if(d < sm){sm = d, smi = p.second;}++j;}ga[i] = smi, gb[i] = mni;st.emplace(make_pair(h[i], i));}
}void init_f()
{for(int j = 1; j <= n; ++j){f[0][j][0] = ga[j];f[0][j][1] = gb[j];}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[1][j][k] = f[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];}}}
}int get_dist(int i, int j)
{return (int)abs(h[i] - h[j]);
}void init_d()
{for(int j = 1; j <= n; ++j){da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);}for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];}}for(int i = 2; i < N; ++i){for(int j = 1; j <= n; ++j){for(int k = 0; k <= 1; ++k){da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];}}}
}void init()
{init_g();init_f();init_d();
}void cal(int s, int x, int& la, int& lb)
{la = lb = 0;for(int i = N - 1; i >= 0; --i){if(f[i][s][0] && la + lb + da[i][s][0] + db[i][s][0] <= x){la += da[i][s][0];lb += db[i][s][0];s = f[i][s][0];}}
}void work()
{int s, x;scanf("%d", &x);int la, lb;int max_h = 0, ans;double min_r = inf, r;for(int i = 1; i <= n; ++i){cal(i, x, la, lb);r = lb ? 1.0 * la / lb : inf;if(r < min_r || r == min_r && h[i] > max_h){ans = i;min_r = r;max_h = h[i];}}printf("%d\n", ans);int m;scanf("%d", &m);while((m--) > 0){scanf("%d %d", &s, &x);cal(s, x, la, lb);printf("%d %d\n", la, lb);}
}int main()
{
//    freopen("input.txt", "r", stdin);read();init();work();return 0;
}

 

这篇关于开车旅行(算法竞赛进阶指南,倍增优化 DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/861656

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python进阶之Excel基本操作介绍

《Python进阶之Excel基本操作介绍》在现实中,很多工作都需要与数据打交道,Excel作为常用的数据处理工具,一直备受人们的青睐,本文主要为大家介绍了一些Python中Excel的基本操作,希望... 目录概述写入使用 xlwt使用 XlsxWriter读取修改概述在现实中,很多工作都需要与数据打交

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

高效管理你的Linux系统: Debian操作系统常用命令指南

《高效管理你的Linux系统:Debian操作系统常用命令指南》在Debian操作系统中,了解和掌握常用命令对于提高工作效率和系统管理至关重要,本文将详细介绍Debian的常用命令,帮助读者更好地使... Debian是一个流行的linux发行版,它以其稳定性、强大的软件包管理和丰富的社区资源而闻名。在使用

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

macOS怎么轻松更换App图标? Mac电脑图标更换指南

《macOS怎么轻松更换App图标?Mac电脑图标更换指南》想要给你的Mac电脑按照自己的喜好来更换App图标?其实非常简单,只需要两步就能搞定,下面我来详细讲解一下... 虽然 MACOS 的个性化定制选项已经「缩水」,不如早期版本那么丰富,www.chinasem.cn但我们仍然可以按照自己的喜好来更换

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南

《Python使用Pandas库将Excel数据叠加生成新DataFrame的操作指南》在日常数据处理工作中,我们经常需要将不同Excel文档中的数据整合到一个新的DataFrame中,以便进行进一步... 目录一、准备工作二、读取Excel文件三、数据叠加四、处理重复数据(可选)五、保存新DataFram