有问题的话欢迎在评论区提出

题意:

题目链接

你是一个送快递的,现在给你一个环,环的边有权值,代表走这条边所花的时间,每个点代表一个地点,点有点权,代表这个点上有多少货物需要你送。初始时间\(t=0\),每到一个点,你就可以瞬间送完该点所有的货物,但每一个货物都会给你带来值为当前时间的罚款。现在你要送完所有货物,问最优情况下你的罚款最少是多少。

题解:

从样例可以看出,这题的核心就在于,快递员可以“反复横跳”,比如可以先逆时针送完一个点的货物,再掉头沿顺时针方向送完所有其它点的货物(尽管这样使得一条边经过了两次,但使得总罚款更少了)。

为了方便下面的说明,先约定些定义:我把起点记做0号点,0号点逆时针走\(j\)格到达的点叫做“逆时针第\(j\)点”,0号点顺时针走\(i\)格到达的点叫做“顺时针第\(i\)点”;

例如,下图中,4号点是顺时针第4点与逆时针第2点。

废话不多说,直接看状态的定义:

\(dp[i][j][0]\):如果\(t=0\)的时候你站在顺时针\(i\)号点,送完包括端点在内,整个\([i,j]\)区间的最小罚款;

\(dp[i][j][1]\):如果\(t=0\)的时候你站在逆时针\(j\)号点,送完包括端点在内,整个\([i,j]\)区间的最小罚款;

有两点值得注意的:

  • 状态定义中假设了\(t=0\)时的位置,但事实上\(t=0\)的时候你是在起点的。为何这么假设呢?往下看就知道了;
  • 上述所谓\([i,j]\)区间,表示的是由i顺时针到j的区间(划重点,也就是说,该区间走的是不含起点的那条路!),这里为了便于理解说成是\([i,j]\),下面也用这种方式表示区间和点,不要搞混了。

那么仍以下图为例,取\(i=1\)和\(j=1\),看看如何更新;

再次强调,该图里的\([i,j]\)区间是\(1,2,3,4,5\)这一段

\(dp[i][j][0]\)可以通过如下两种方式更新(特别提醒,由于\(t=0\)时你就在顺时针第\(i\)个位置,所以\(i\)处的货物不带来任何罚款,这也是下面两种情况中我们都无视了\(i\)点罚款的原因):

  • 走到\(i+1\),这样做的花费是 : \(dp[i+1][j][0]+\)( 区间\([i+1,j]\)的货物数量之和 \(*i\)与\(i+1\)点间的时间 )

    解释:\(dp[i][j][0]\)假设\(t=0\)的时候你在\(i\)处,而\(dp[i+1][j][0]\)的\(t=0\)时刻假设你在\(i+1\)处,因此,两者的“开始时间”有个差距,即“\(i\)到\(i+1\)的时间”,该时间的影响是平均的作用在该区间所有货物上的。
  • 掉头走到\(j\),这样做的花费是 : \(dp[i+1][j][1]+\)( 区间\([i+1,j]\)的货物数量之和 \(*i\)掉头走到\(j\)点的时间 )

    解释:与上面的情况对比,仍然是\([i+1,j]\)中的所有货物都统一的被拖延了一个时间,只不过这次该时间变成了\(i\)到\(j\)的一条路的时间

最终,\(dp[i][j][0]\)的值就取这两者与自己之间的最小值,就可以完成更新。

\(dp[i][j][1]\)的更新同理,可以参考下面dfs函数内写的方法。

后记:

最开始,我定义的\(dp[i][j][0]\)是“由\(i\)逆时针到\(j\)全部送完的最小罚款”,也就是走含起点的那一条路,相信应该会有一些人第一反应也这么想吧。但这样搞的话,似乎就没法转移了,因为你没法处理掉头多次的情况。

总之,第一反应能想到一个正确的状态,真的很重要。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
int n,num[310],len[310],lpre[310],npre[310];
int dp[310][310][2];
int nsum(int i,int j){
int tmp=(i!=0);j=n-j;
return npre[j]-npre[i-tmp];
}
int lsum(int i,int j){
return lpre[j]-lpre[i];
}
int dfs(int i,int j,int pos){
if(dp[i][j][pos]!=inf){
return dp[i][j][pos];
}
if(i+j>=n){
return dp[i][j][pos]=0;
}
if(pos==1){
dp[i][j][1]=min(dp[i][j][1],dfs(i,j+1,1)+len[n-(j+1)]*nsum(i,j+1));
dp[i][j][1]=min(dp[i][j][1],dfs(i,j+1,0)+(lpre[i]+lsum(n-j,n))*nsum(i,j+1));
}
else{
dp[i][j][0]=min(dp[i][j][0],dfs(i+1,j,0)+len[i]*nsum(i+1,j));
dp[i][j][0]=min(dp[i][j][0],dfs(i+1,j,1)+(lpre[i]+lsum(n-j,n))*nsum(i+1,j));
}
return dp[i][j][pos];
}
int main(){
while(~scanf("%d",&n)){
if(!n) break;
for(int i=0;i<n;i++){
scanf("%d%d",&num[i],&len[i]);
}
lpre[0]=npre[0]=num[n]=0;
for(int i=1;i<=n;i++){
lpre[i]=lpre[i-1]+len[i-1];
npre[i]=npre[i-1]+num[i];
}
memset(dp,inf,sizeof(dp));
int ans=min(dfs(0,0,0),dfs(0,0,1));
printf("%d\n",ans);
}
return 0;
}

POJ 2671 Jimmy's Bad Day题解(很详细很友好,类似区间dp)的更多相关文章

  1. Solr调研总结(很详细很全面)

    Solr调研总结 开发类型 全文检索相关开发 Solr版本 4.2 文件内容 本文介绍solr的功能使用及相关注意事项;主要包括以下内容:环境搭建及调试;两个核心配置文件介绍;维护索引;查询索引,和在 ...

  2. 很详细很详细的gitLab使用具体流程

    gitLab详细流程 先说一下整个流程,就是先建立一个项目-----拆分里程碑-----拆分issue----项目开发-----项目总结---关闭里程碑 下面是每个步骤具体的步骤,这个比较适合那种纯新 ...

  3. redis的集群搭建(很详细很详细)

    说在前面的话 之前有一节说了redis单机版的搭建和使用jedis管理redis单机版和集群版, 本节主要讲一下redis的集群搭建. 跳转到jedis管理redis的使用 认识redis集群 首先我 ...

  4. POJ 2995 Brackets 区间DP

    POJ 2995 Brackets 区间DP 题意 大意:给你一个字符串,询问这个字符串满足要求的有多少,()和[]都是一个匹配.需要注意的是这里的匹配规则. 解题思路 区间DP,开始自己没想到是区间 ...

  5. POJ 1390 Blocks(区间DP)

    Blocks [题目链接]Blocks [题目类型]区间DP &题意: 给定n个不同颜色的盒子,连续的相同颜色的k个盒子可以拿走,权值为k*k,求把所有盒子拿完的最大权值 &题解: 这 ...

  6. POJ 1179 - Polygon - [区间DP]

    题目链接:http://poj.org/problem?id=1179 Time Limit: 1000MS Memory Limit: 10000K Description Polygon is a ...

  7. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  8. POJ 1160 经典区间dp/四边形优化

    链接http://poj.org/problem?id=1160 很好的一个题,涉及到了以前老师说过的一个题目,可惜没往那上面想. 题意,给出N个城镇的地址,他们在一条直线上,现在要选择P个城镇建立邮 ...

  9. poj 3280(区间DP)

    Cheapest Palindrome Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7869   Accepted: 38 ...

随机推荐

  1. Synchronized加锁、锁升级和java对象内存结构

    首先了解一下JMM中定义的内存操作: 一个线程操作数据时候都是从主内存(堆内存)读取到自己工作内存(线程私有的数据区域)中再进行操作.对于硬件内存来说,并没有工作内存和主内存的区分,这都是java内存 ...

  2. 【Kafka】数据分区策略

    数据分区策略 四种策略 一.指定分区号,数据会直接发送到所指定的分区 二.没有指定分区号,指定了数据的key,可以通过key获取hashCode决定数据发送到哪个分区 三.都没有指定的话,会采取rou ...

  3. 安卓集成Unity开发示例(一)

    本项目目的是在移动端的 Native App 中以库的形式集成已经写好的 Unity 工程,利用 Unity 游戏引擎便捷的开发手段进行跨平台开发. Unity官方文档 Unity as a Libr ...

  4. 一阶RC高通滤波器详解(仿真+matlab+C语言实现)

    文章目录 预备知识 关于电容 HPF的推导 simulink 仿真 simulink 运行结果 matlab 实现 matlab 运行结果 C语言实现 如果本文帮到了你,帮忙点个赞: 如果本文帮到了你 ...

  5. Excel非常规快捷键

    Windows+V,调出剪贴板,是常规快捷键,鼠标右键-W-F,新建文件夹,这是非常规快捷键. 掌握Excel大半菜单和三五十快捷键,Excel也算入门了.对Excel快捷键的学习,其一是常规快捷键, ...

  6. hdu2336 (匈牙利最大匹配+二分)

    Describe 这是一个简单的游戏,在一个n*n的矩阵中,找n个数使得这n个数都在不同的行和列里并且要求这n个数中的最大值和最小值的差值最小. Input 输入一个整数T表示T组数据. 对于每组数据 ...

  7. 腾讯面试居然跟我扯了半小时的CountDownLatch

    一个长头发.穿着清爽的小姐姐,拿着一个崭新的Mac笔记本向我走来,看着来势汹汹,我心想着肯定是技术大佬吧!但是我也是一个才华横溢的人,稳住我们能赢. 面试官:看你简历上有写熟悉并发编程,CountDo ...

  8. python爬虫-vmgirls-正则表达式

    概述 本次爬虫任务是爬取图片网站图片,网址是https://www.vmgirls.com/ 分析网页 第一步,打开需要爬取的页面https://www.vmgirls.com/13344.html ...

  9. vue学习-第三个DEMO(计算属性和监视) v-model基础用法

    <div id="demo"> 姓:<input type="text" placeholder="First Name" ...

  10. 萌新学习SpringMVC

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 这篇SpringMVC被催了很久了,这阵子由于做 ...