描述

小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市——那座城市即将举行美食节!

但是不幸的是,小Hi和小Ho并没有能够买到很好的火车票——他们只能够乘坐最为破旧的火车进行他们的旅程。

不仅如此,因为美食节的吸引,许多人纷纷踏上了和小Hi小Ho一样的旅程,于是有相当多的人遭遇到了和小Hi小Ho一样的情况——这导致这辆车上的人非常非常的多,以至于都没有足够的位置能让每一个人都有地方坐下来。

小Hi和小Ho本着礼让他们的心情——当然还因为本来他们买的就是站票,老老实实的呆在两节车厢的结合处。他们本以为就能够这样安稳抵达目的地,但事与愿违,他们这节车厢的乘务员是一个强迫症,每隔一小会总是要清扫一次卫生,而时值深夜,大家都早已入睡,这种行为总是会惊醒一些人。而一旦相邻的一些乘客被惊醒了大多数的话,就会同乘务员吵起来,弄得大家都睡不好。

将这一切看在眼里的小Hi与小Ho决定利用他们的算法知识,来帮助这个有着强迫症的乘务员——在不与乘客吵起来的前提下尽可能多的清扫垃圾。

小Hi和小Ho所处的车厢可以被抽象成连成一列的N个位置,按顺序分别编号为1..N,每个位置上都有且仅有一名乘客在休息。同时每个位置上都有一些垃圾需要被清理,其中第i个位置的垃圾数量为Wi。乘务员可以选择其中一些位置进行清理,但是值得注意的是,一旦有编号连续的M个位置中有超过Q个的位置都在这一次清理中被选中的话(即这M个位置上的乘客有至少Q+1个被惊醒了),就会发生令人不愉快的口角。而小Hi和小Ho的任务是,计算选择哪些位置进行清理,在不发生口角的情况下,清扫尽可能多的垃圾。

提示一:无论是什么动态规划,都需要一个状态转移方程!

提示二:好像什么不对劲?状态压缩哪里去了?

 

提示一:无论是什么动态规划,都需要一个状态转移方程!

小Hi面对这个问题也是不慌不忙,反倒决定借此机会让小Ho学习一下状态压缩动态规划,于是推了推一旁仍然晕晕乎乎的小Ho,问道:“小Ho,你说这样的问题能否使用动态规划进行解决?”

小Ho思索了一番,在心中默默将这个问题与背包问题进行类比后,道:“我觉得似乎不可以,这个问题和背包问题其实是很类似的,不过背包问题对于选取物品的限制是总重量不能超过一定数额。但在这里却是要求不能够在连续的一段位置中选取太多,如果我仍然以编号从小到大划分阶段,单单以best(i)表示当前已经决定了编号为1..i的位置是否选取的情况下最多可以清扫的垃圾数量的话,因为我不知道之前具体的选取方案,我是没有办法判断当前这个位置能否进行选取的,这便是违反了动态规划状态定义的无后效性!

小Hi点了点头表示赞同,但随即继续问道:”在背包问题中,正如我们之前经历时所说,我们是通过将best(i)变成best(i, j),增加一个量——当前已经选取物品的总重量j到状态中,从而能够判断当前是否能够继续选取物品,那么在这里,你觉得我们需要添加什么样的量才能够达成我们的目的呢?”

这个问题顿时难倒了小Ho,但他也不是轻易放弃的性格,便拿出纸笔开始写写画画:“正如我之前所说,我不知道之前具体的选取方案,我是肯定没有办法判断当前这个位置能否进行选取的!那么我需要做的事情无非就是在状态中记录之前的选取方法,并且这些记录需要能够让我推算出当前这个位置的垃圾是否能被清扫而不引起口角!”

思路一旦清晰,各种想法便接踵而至,小Ho思索片刻便得出了结论:“如果我将之前每一个位置是否选取的信息都存储下来的话,那么到了决定最后一个位置的时候,最坏情况下我就有2^(N-1)种可能的状态,这个是我所不能接受的,但是我真的需要这么多的信息么?”

“不需要!”小Ho说道:“我只需要知道我之前的M-1个位置中选取了多少个位置就可以了!如果这个数目小于Q,那么我当前就有两种决策方案——选与不选,不然就就只有不选这一种方案。”

小Hi听闻此言,皱了皱眉头,问道:“那你的状态难道就要定义成best(i, j)表示当前已经决定了编号为1..i的位置,并且从i-M+1 ... i-1这M-1个位置中已经选取了j个位置的情况下最多可以清扫的垃圾数量么?”

小Ho刚想称是,却想道小Hi不会无缘无故的问这种问题,于是仔细考虑,顿时发现其中不对:“状态固然是可以了,但是却没有办法进行转移,best(i, j)的下一步肯定是某个best(i+1, k),但是因为无法知晓i-M+1这个位置究竟是否在j个选取的位置中,所以是根本没有办法计算k的!

“而一旦记录了i-M+1这个位置是否选取了的话,我就还需要记录i-M+2这个位置——因为在best(i+1, k)中它便是(i+1)-M+1的这个位置,以此类推,也就是说我不能够光记录从i-M+1 ... i-1 这M-1个位置中选取了多少个位置,我还要将具体选择了哪些位置都一一记录下来!”小Ho思考道:“那我便只有如此定义状态了——以best(i, p1, p2, p3, ... , pM-1)表示当前已经决定了编号为1..i的位置,并且第(i-j+1)个位置是否选取用pj进行记录(0表示未选取,1表示选取)的情况下最多可以清扫的垃圾数量!

听完小Ho新的想法,小Hi终于点了点头,但也没放弃继续考校小Ho:“那你准备如何转移状态?”

“这个简单,我只需要统计p1..pM-1之和S——即选取的位置总数,并且根据这个数目进行决策!”小Ho说罢在纸上写出一个公式。

“那具体的计算顺序呢?”小Hi也是将每个步骤都问的详详细细的。

小Ho张口便道:“这个容易,因为每次转移都是从i向i+1进行的,所以我只需要按照i从小到大的顺序进行计算就可以了!”

 
 

提示二:好像什么不对劲?状态压缩哪里去了?

在得出结论之后,小Ho便拿出笔记本开始写程序,写着写着便注意到:“这个M是根据输入来的,那么我怎么开数组呢!难道要使用一些动态的方法?这样也未免太过复杂了吧,更何况即使我动态的开了数组,我也没有很好的方法来枚举这些位置,难道要写一大串的条件分支语句?”

思索无奈之下,只能够去询问小Hi,小Hi仿佛早就预料到了这个情况,掏出一张草稿纸来,写下了一个长度为5的01串10101,问道:“你看这是什么?”

“一个2进制串?我算算……等于21?”小Ho耿直的算了出来。

小Hi笑了笑“如果我说这便是M=6的情况下,以第一个01来表示你状态中的p1,第二个01来表示你状态中的p2,并依次类推,那么我是否可以用(i, 21)来表示你的(i, 1, 0, 1, 0, 1)这样一个状态呢?”

小Ho顿时恍然大悟:“是了!既然是01串,那么我就将这M-1个01视作一个二进制数又有何不可!这样一来,我的状态和状态转移方程岂非可以这样定义?”

“是的!这便是所说的状态压缩,它在处理一些变长/变维度的状态时时非常有效的,同时也可以利用位运算来优化代码,方便计算!”小Hi适时的做了总结。

“嗯嗯!我这便去写~”

 

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为三个正整数N、M和Q,意义如前文所述。

每组测试数据的第二行为N个整数,分别为W1到WN,代表每一个位置上的垃圾数目。

对于100%的数据,满足N<=1000, 2<=M<=10,1<=Q<=M, Wi<=100

输出

对于每组测试数据,输出一个整数Ans,表示在不发生口角的情况下,乘务员最多可以清扫的垃圾数目。

Sample Input

5 2 1
36 9 80 69 85

Sample Output

201
 /*
状态压缩DP
问题 连续的1到n个位置,问在连续m个位上清扫垃圾不打扰超过q位乘客的情况下,最多能清扫多少垃圾
抽象问题 在前i个位置里,连续m个位置上清扫垃圾不打扰超过q位乘客的情况下,最多能清扫多少垃圾
变量 i,m个位置上状态(清理为1,不清理为0),最多能清理多少垃圾
定义状态 以best[i][p1,p2,p3,...pm-1]表示在前i个位置里,连续m个位置上清扫垃圾不打扰超过q位乘客的情况下,最多能清扫多少垃圾
并且以pj(j=1,2,3,..m-1)表示对应位置上是否清理,1表示清理,0表示不清理 由于第二个变量长度及位数不确定,用数组模拟实现较为麻烦,所以将其状态压缩为一个十进制数(巧妙的看成m位的二进制数) 状态转移 当枚举的j里二进制数中1的个数小于等于q时,表示当前位置i可以清理,可以清理表示可清可不清
当j的末尾位置为1,就是决定清理,则best[i][j]为前i-1个位置里清扫和不清扫的中的最大值加上当前位置垃圾量
即best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]) + w[i];
当j的末尾位置为0,就是决定不清理,则best[i][j]为前i-1个位置里清扫和不清扫的中的最大值(有点更新的意思)
即best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]);
当枚举的j里二进制数中1的个数大于q时,表示当前位置只能是不清理,best[i][j]也为前i-1个位置里清扫和不清扫的中的最大值
即best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]); 具体实现时,i推出i+1,则i递增
j根据枚举的二进制数的从小到大,也是递增
*/
#include<stdio.h>
#include<string.h>
int n,m,q;
int w[];
int best[][];
int max(int x, int y){
return x > y ? x : y;
}
int one_num(int x);
int main()
{
int i,j;
while(scanf("%d%d%d",&n,&m,&q) != EOF)
{
for(i=;i<=n;i++){
scanf("%d",&w[i]);
}
memset(best,,sizeof(best));
for(i=;i<=n;i++){
for(j=;j < (<<m);j++){
/*if(one_num(j) <= q){
if(j & 1)
best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]) + w[i];
else
best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]);
}
else
best[i][j]=max(best[i-1][j>>1],best[i-1][(j>>1) + (1<<(m-1))]);*/
best[i][j]=max(best[i-][j>>],best[i-][(j>>) + (<<(m-))]);
if(one_num(j) <= q){
if(j & )
best[i][j] += w[i];
}
}
}
int ans=-;
for(i=;i< <<m;i++){
if(ans < best[n][i])
ans=best[n][i];
}
printf("%d\n",ans);
}
return ;
}
int one_num(int x)
{
int num=;
while(x){
if(x & )
num++;
x >>= ;
}
return num;
}

状态压缩·一(状态压缩DP)的更多相关文章

  1. 状态压缩动态规划 状压DP

    总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...

  2. Reverse Core 第二部分 - 14&15章 - 运行时压缩&调试UPX压缩的notepad

    @date: 2016/11/29 @author: dlive 0x00 前言 周六周日两天在打HCTF2016线上赛,没时间看书,打完比赛接着看~~ 0x01 运行时压缩 对比upx压缩前后的no ...

  3. http协议和web应用有状态和无状态浅析

    http协议和web应用有状态和无状态浅析 (2013-10-14 10:38:06) 转载▼ 标签: it   我们通常说的web应用程序的无状态性的含义是什么呢? 直观的说,“每次的请求都是独立的 ...

  4. python(30) 获取网页返回的状态码,状态码对应问题查询

    获取访问网页返回的状态码 html = requests.get(Url) respon = html.status_code 以下内容来自于维基百科:点击查看网页 1xx消息 这一类型的状态码,代表 ...

  5. REST有状态与无状态的理解

    1. 什么是REST? REST(REpresentation State Transfer)表述性状态传递,是一种软件架构风格,是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可 ...

  6. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

  7. 解剖SQLSERVER 第十三篇 Integers在行压缩和页压缩里的存储格式揭秘(译)

    解剖SQLSERVER 第十三篇    Integers在行压缩和页压缩里的存储格式揭秘(译) http://improve.dk/the-anatomy-of-row-amp-page-compre ...

  8. myisam压缩(前缀压缩)索引

    myisam使用前缀压缩来减少索引的大小,从而让更多的索引可以放入内存中,默认只压缩字符串,但通过参数配置也可以对整数做压缩,myisam压缩每个索引块的方法是,先完全保存索引块中的第一个值,然后将其 ...

  9. ARM状态和THUMB状态

    ARM处理器的工作状态 在ARM的体系结构中,可以工作在三种不同的状态,一是ARM状态,二是Thumb状态及Thumb-2状态,三是调试状态. <嵌入式系统开发与应用教程(第2版)>上介绍 ...

  10. linux 压缩文件 及压缩选项详解

    本文介绍linux下的压缩程序tar.gzip.gunzip.bzip2.bunzip2.compress.uncompress. zip. unzip.rar.unrar等程式,以及如何使用它们对. ...

随机推荐

  1. shell 命令 mkdir -p

    开发中我们会遇到嵌套创建文件目录的需要,这时需要用到 mkdir -p 比如我要在本地嵌套创建 /Users/dairui/Downloads/zookeeper/dataLogDir目录 直接使用 ...

  2. 深入探讨 Java 类加载器(转)

    原帖地址:https://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要 ...

  3. XE7 & FMX 那些年我们一起上过的控件:ListView 之 (3) 加载数据时如何显示自定义样式

    本文介绍一下ListView下如何加载数据.及使用进度条反馈当前进度给用户. 注意: 原创作品,请尊重作者劳动成果,转载请注明出处!!!原文永久固定地址:http://www.cnblogs.com/ ...

  4. hdu 1.3.1 FatMouse' Trade

    贪心的运用,主要看其比值,取最大值实现贪心... #include<cstdio> #include<algorithm> #include<vector> usi ...

  5. netcore 发布 到 windows server IIS

    net core 和普通net 发布没有什么不同,只需要在个别地方注意下: 1. 在visual Studio 2017 发布 2. 把发布好的文件copy到服务器上,并新建一个网站,同时要注意选择无 ...

  6. Python2.7更新pip:UnicodeDecodeError: 'ascii' codec can't decode byte 0xb7 in position 7: ordinal not in range(128)

    1.首先更新pip版本的时候出现.这是出现在python2.7.16出现的问题 2.进入你的pyhton目录下的Lib\mimetypes.py 打开它 3.在import下面加入这代码 if sys ...

  7. POJ 2442(优先队列 k路归并 堆)

    Description Given m sequences, each contains n non-negative integer. Now we may select one number fr ...

  8. spring-boot集成mybatis,用redis做缓存

    网上有很多例子了,执行源码起码有3个,都是各种各样的小问题. 现在做了个小demo,实现spring-boot 用redis做缓存的实例,简单记录下思路,分享下源码. 缓存的实现,分担了数据库的压力, ...

  9. ASP.NETCore学习记录(一)

    ASP.NETCore学习记录(一) asp.net core介绍  Startup.cs  ConfigureServices  Configure  0. ASP.NETCore 介绍 ASP.N ...

  10. [原创]K8 MSF Bind Shell TCP 连接工具

    工具: K8_MSFBindShellClient_20170524[K.8]编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.1 ...