Codeforces 1503C Travelling Salesman Problem(Dynamic Programming)
题意
大家都是优秀生,这点英文还是看得懂的:点此看题
题解
由于旅行路线成一个环,所以从哪里出发不重要,我们把景点按照
a
i
a_i
ai 排序,不妨就从左边最小的出发。基础的旅行费用
c
i
c_i
ci 是都要算上的,我们的目的是最小化额外的费用
∑
max
(
0
,
(
a
j
−
a
i
)
−
c
j
)
\sum\max(0,(a_j-a_i)-c_j)
∑max(0,(aj−ai)−cj) 。
很明显有一部分的景点是回程(从大到小飞回起点)的时候经过的,这些景点一定没有额外费用。其它景点是来路经过的,费用取决于相邻两个的“间距”(
a
a
a 的差)。最左端和最右端都在来路上。
我们不妨用
d
p
[
i
]
dp[i]
dp[i] 表示来路上经过
i
i
i 时,最小的额外花费是多少。那么假设从
i
i
i 往左数,直到
k
k
k 以内的前驱,到
i
i
i 的额外花费都是 0(这个 k 可以预处理出来),则转移为:
d
p
[
i
]
=
min
{
min
j
=
k
i
−
1
d
p
[
j
]
,
a
i
+
(
min
j
=
1
k
−
1
(
d
p
[
j
]
−
a
j
)
)
−
c
i
}
dp[i]=\min\bigg\{\min_{j=k}^{i-1} dp[j]~,~a_i+\big(\min_{j=1}^{k-1} (dp[j]-a_j)\big)-c_i\bigg\}
dp[i]=min{j=kmini−1dp[j] , ai+(j=1mink−1(dp[j]−aj))−ci}
可以分别建立两棵线段树来优化
D
P
\rm DP
DP 。时间复杂度
Θ
(
n
log
n
)
\Theta(n\log n)
Θ(nlogn) 。
CODE
和上面说的不同,这个是从右到左算的。
#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
int n,m,i,j,s,o,k;
struct it{
int a,c,id;
}p[MAXN];
LL dp[MAXN];
bool cmp(it x,it y) {
if(x.a != y.a) return x.a < y.a;
if(x.id == 1) return 1;
if(y.id == 1) return 0;
return x.c < y.c;
}
int tre1[MAXN<<2],tre2[MAXN<<2],M;
int bing1(int x,int y) {
if(!x || !y) return x+y;
if(dp[x] != dp[y]) return dp[x] < dp[y] ? x:y;
return max(x,y);
}
int bing2(int x,int y) {
if(!x || !y) return x+y;
if(dp[x]+p[x].a != dp[y]+p[y].a) return dp[x]+p[x].a < dp[y]+p[y].a ? x:y;
return max(x,y);
}
void maketree(int n) {M=1;while(M<n+2)M<<=1;}
void addtree(int x,int y) {
int s = M+x;tre1[s] = tre2[s] = y;s >>= 1;
while(s) tre1[s] = bing1(tre1[s<<1],tre1[s<<1|1]),tre2[s] = bing2(tre2[s<<1],tre2[s<<1|1]),s >>= 1;
}
int findtree1(int l,int r) {
int as = 0; if(l > r) return as;
int s = M+l-1,t = M+r+1;
while(s || t) {
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) as = bing1(as,tre1[s^1]);
if(t & 1) as = bing1(as,tre1[t^1]);
}else break;
s >>= 1;t >>= 1;
}return as;
}
int findtree2(int l,int r) {
int as = 0; if(l > r) return as;
int s = M+l-1,t = M+r+1;
while(s || t) {
if((s>>1) ^ (t>>1)) {
if(!(s & 1)) as = bing2(as,tre2[s^1]);
if(t & 1) as = bing2(as,tre2[t^1]);
}else break;
s >>= 1;t >>= 1;
}return as;
}
int rr[MAXN];
int main() {
n = read();
LL ans = 0;
for(int i = 1;i <= n;i ++) {
p[i].a = read();p[i].c = read();
ans += p[i].c;
p[i].id = i;
}
sort(p + 1,p + 1 + n,cmp);
maketree(n);
for(int i = 1;i < n;i ++) {
rr[i] = i;
for(int j = 17;j >= 0;j --) {
if(rr[i]+(1<<j) <= n && p[rr[i]+(1<<j)].a <= p[i].a+p[i].c) rr[i] += (1<<j);
}
}
dp[n] = 0;
addtree(n,n);
for(int i = n-1;i > 0;i --) {
int t1 = findtree1(i+1,rr[i]),t2 = findtree2(rr[i]+1,n);
dp[i] = 1e18;
if(t1) dp[i] = min(dp[i],dp[t1]);
if(t2) dp[i] = min(dp[i],dp[t2] + p[t2].a - (p[i].a+p[i].c));
addtree(i,i);
}
printf("%lld\n",ans + dp[1]);
return 0;
}
Codeforces 1503C Travelling Salesman Problem(Dynamic Programming)的更多相关文章
- PAT A1150 Travelling Salesman Problem (25 分)——图的遍历
The "travelling salesman problem" asks the following question: "Given a list of citie ...
- 1150 Travelling Salesman Problem(25 分)
The "travelling salesman problem" asks the following question: "Given a list of citie ...
- hdu 5402 Travelling Salesman Problem(大模拟)
Problem Description Teacher Mai ,) to the bottom right corner (n,m). He can choose one direction and ...
- #C++初学记录(动态规划(dynamic programming)例题1 钞票)
浅入动态规划 dynamic programming is a method for solving a complex problem by breaking it down into a coll ...
- 详解动态规划(Dynamic Programming)& 背包问题
详解动态规划(Dynamic Programming)& 背包问题 引入 有序号为1~n这n项工作,每项工作在Si时间开始,在Ti时间结束.对于每项工作都可以选择参加与否.如果选择了参与,那么 ...
- 笔试算法题(44):简介 - 动态规划(Dynamic Programming)
议题:动态规划(Dynamic Programming) 分析: DP主要用于解决包含重叠子问题(Overlapping Subproblems)的最优化问题,其基本策略是将原问题分解为相似的子问题, ...
- HDU 5402 Travelling Salesman Problem (模拟 有规律)(左上角到右下角路径权值最大,输出路径)
Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 65536/65536 K (J ...
- 对动态规划(Dynamic Programming)的理解:从穷举开始(转)
转自:http://janfan.cn/chinese/2015/01/21/dynamic-programming.html 动态规划(Dynamic Programming,以下简称dp)是算法设 ...
- hdu 5402 Travelling Salesman Problem (技巧,未写完)
题意:给一个n*m的矩阵,每个格子中有一个数字,每个格子仅可以走一次,问从(1,1)走到(n,m) 的路径点权之和. 思路: 想了挺久,就是有个问题不能短时间证明,所以不敢下手. 显然只要n和m其中一 ...
随机推荐
- es6.4.2api
这是讲数据库的数据导入到es里 所有用到了mysql! 1.依赖 <?xml version="1.0" encoding="UTF-8"?> & ...
- 将 Ubuntu 16.04 LTS 的 Unity 启动器移动到桌面底部命令
将 Ubuntu 16.04 LTS 的 Unity 启动器移动到桌面底部命令: gsettings set com.canonical.Unity.Launcher launcher-positio ...
- .NET中按预定顺序执行任务
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月1日. 一.说明 在.NET中线程可以定义按先后顺序进行执行,适合部分有先后次序的业务逻辑.Task也可以按照预定义的先后顺序执行 ...
- Cascade-LSTM: A Tree-Structured Neural Classifier for Detecting Misinformation Cascades(KDD20)
Cascade-LSTM是一个用于虚假信息级联检测的树结构神经分类器,它本质上是一个谣言(假新闻)检测模型,它将谣言检测任务视为一个树分类问题. Cascade-LSTM在递归神经网络(本文具体基于T ...
- HTML 超文本标记语言 (Hyper Text Markup Language)
1.HTML是什么 HTML指的超文本标记语言(Hyper Text Markup Language),是一种用来描述网页的语言.超文本指的是除了可以包含文字之外,还可以包含图片.链接.音乐.视频.程 ...
- 在矩池云使用Disco Diffusion生成AI艺术图
在 Disco Diffusion 官方说明的第一段,其对自身是这样定义: AI Image generating technique called CLIP-Guided Diffusion.DD ...
- 千位分隔符在web开发中的作用
有千位分隔符会被认为是数字,否则在移动端会被直接识别成手机号 在开发实战中主流实现方式是添加meta标签 <meta name="format-detection" cont ...
- 一款 IDEA 插件帮你优雅转化 DTO、VO、BO、PO、DO
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.承认你优秀很难 很多码农,把路走窄了 捧一个,喷一个,很多码农都不会多一点思路看问题,总是 ...
- freeswitch的话单模块
概述 最近因为业务需要,在看freeswitch中话单相关的一些模块. 在voip的使用过程中,话单是重要的基础模块,涉及到计费和问题查找. 呼叫话单最重要的一点是稳定,不能有错误或遗漏. 本章对fs ...
- windows10:vscode下go语言的适配
ps:本篇依赖golang的sdk已经安装完成: url:https://www.cnblogs.com/mrwhite2020/p/16475731.html 一.下载vscode,选择wind ...