开车旅行(算法竞赛进阶指南,倍增优化 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

相关文章

CentOS7更改默认SSH端口与配置指南

《CentOS7更改默认SSH端口与配置指南》SSH是Linux服务器远程管理的核心工具,其默认监听端口为22,由于端口22众所周知,这也使得服务器容易受到自动化扫描和暴力破解攻击,本文将系统性地介绍... 目录引言为什么要更改 SSH 默认端口?步骤详解:如何更改 Centos 7 的 SSH 默认端口1

SpringBoot多数据源配置完整指南

《SpringBoot多数据源配置完整指南》在复杂的企业应用中,经常需要连接多个数据库,SpringBoot提供了灵活的多数据源配置方式,以下是详细的实现方案,需要的朋友可以参考下... 目录一、基础多数据源配置1. 添加依赖2. 配置多个数据源3. 配置数据源Bean二、JPA多数据源配置1. 配置主数据

MySQL索引的优化之LIKE模糊查询功能实现

《MySQL索引的优化之LIKE模糊查询功能实现》:本文主要介绍MySQL索引的优化之LIKE模糊查询功能实现,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录一、前缀匹配优化二、后缀匹配优化三、中间匹配优化四、覆盖索引优化五、减少查询范围六、避免通配符开头七、使用外部搜索引擎八、分

python中各种常见文件的读写操作与类型转换详细指南

《python中各种常见文件的读写操作与类型转换详细指南》这篇文章主要为大家详细介绍了python中各种常见文件(txt,xls,csv,sql,二进制文件)的读写操作与类型转换,感兴趣的小伙伴可以跟... 目录1.文件txt读写标准用法1.1写入文件1.2读取文件2. 二进制文件读取3. 大文件读取3.1

SpringBoot中配置Redis连接池的完整指南

《SpringBoot中配置Redis连接池的完整指南》这篇文章主要为大家详细介绍了SpringBoot中配置Redis连接池的完整指南,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以... 目录一、添加依赖二、配置 Redis 连接池三、测试 Redis 操作四、完整示例代码(一)pom.

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

PyInstaller打包selenium-wire过程中常见问题和解决指南

《PyInstaller打包selenium-wire过程中常见问题和解决指南》常用的打包工具PyInstaller能将Python项目打包成单个可执行文件,但也会因为兼容性问题和路径管理而出现各种运... 目录前言1. 背景2. 可能遇到的问题概述3. PyInstaller 打包步骤及参数配置4. 依赖

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.