难点在于状态设计,从左向右一本书一本书的考虑,每本书的决策有两种拿走或者留下,

对于拿走后的书,之后要放回,但是决策过程中不知道到往哪里放,

虽然前面的书的种类确定,可能是往后面放更优,而后面的书的类型还不确定。对于所有拿出来的书,最后会增加多少段只和书的种类有关。

所以我们用s记录留下书的种类,等到所有书都考虑完了以后一并放回。

对于留下的书,是否成为新的一段和上一次书的高度有关,因此用一个last记录上一次书的种类。(用s来判断一下last不存在的情况)

dp[i = 第i本书][j = 拿了j次][s = 剩下书的种类][last = 上一次书的种类] = 最小混乱度

转移方程见代码

直接for是最好写的

#include<bits/stdc++.h>
using namespace std; const int maxn = , maxs = <<;
int dp[][maxn][maxs][];
int bc[maxs];
int h[maxn];
const int INF = 0x3f3f3f3f; //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
for(int i = maxs; i-- ;){
int x = i;
while(x){;
bc[i] += x&;
x >>= ;
}
}
int ks = , n, k;
while(scanf("%d%d",&n,&k),n+k){
int All = ;
for(int i = ; i < n; i++){
scanf("%d",h+i);
h[i] -= ;
All |= <<h[i];
}
memset(dp[],0x3f,sizeof(dp[]));
dp[][][<<h[]][h[]] = ;
dp[][][][] = ;
for(int i = ; i < n; i++){
int a = i&, b = a^, bs = <<h[i];
memset(dp[a],0x3f,sizeof(dp[a]));
for(int j = k; j >= ; j--){
for(int s = maxs; s--; ){
for(int ls = ; ls--; ){
if(dp[b][j][s][ls] < INF){
dp[a][j][s|bs][h[i]] = min(dp[a][j][s|bs][h[i]], dp[b][j][s][ls] + (s?( h[i] == ls?: ):));
if(j < k) dp[a][j+][s][ls] = min(dp[a][j+][s][ls], dp[b][j][s][ls]);
}
}
}
}
}
int a = n&^;
int ans = n+;
for(int s = maxs; s--;){
for(int ls = ; ls--; ){
ans = min(ans, dp[a][k][s][ls] + bc[All^s]);
}
}
printf("Case %d: %d\n\n",++ks,ans);
}
return ;
}

实际上可能有很多状态访问不到的时候,for会枚举到一些无用的状态,这时候可以考虑把有效的状态保存下来,(记忆化搜索也可以避免访问无用状态,但是没办法用滚动数组了)

这样的话不需要对整个dp数组初始化,取代的是需要状态判重。

这样写有种做搜索题的感觉。

#include<bits/stdc++.h>
using namespace std; const int maxn = , maxs = <<;
int dp[][maxn][][maxs];
int vis[maxn][][maxs],clk; int h[maxn]; const int nil = ;
struct state
{
int ct,ls,s;
}vc[][maxn**maxs]; int sz[];
#define dim(x) [x.ct][x.ls][x.s]
#define add(id,ct,ls,s) vc[id][sz[id]++] = state{ct,ls,s};
#define psb(id) vc[id][sz[id]++] = y;
#define clr(id) sz[id] = 0;
#define edof(id) vc[id][sz[id]] #define updata(v)\
if(vis Td != clk){\
vis Td = clk;\
dp[a] Td = v;\
psb(a);\
}else {\
dp[a] Td = min(dp[a] Td, v);\
} inline int bc(int x)
{
int re = ;
while(x){
re += x&;
x >>= ;
}
return re;
} //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int ks = , n, k;
while(scanf("%d%d",&n,&k),n+k){
int All = ;
for(int i = ; i < n; i++){
scanf("%d",h+i);
h[i] -= ;
All |= <<h[i];
}
clr();
state y = {,h[],<<h[]};
dp[] dim(y) = ;
psb()
y = {,nil,};
dp[] dim(y) = ;
psb()
for(int i = ; i < n; i++){
int a = i&, b = a^, bs = <<h[i];
clr(a)
clk++;
for(int j = ; j < sz[b]; j++){
auto &x = vc[b][j];
int val = dp[b] dim(x);
int tmp = val + ( x.s? ( (x.ls == h[i])?: ) : );
y = {x.ct,h[i],x.s|bs};
#define Td [y.ct][y.ls][y.s]
updata(tmp)
if(x.ct < k){
y = {x.ct+, x.ls, x.s};
updata(val)
}
}
}
int a = n&^;
int ans = n+;
for(int j = ; j < sz[a]; j++){
auto &x = vc[a][j];
ans = min(ans, dp[a] dim(x) + bc(All^x.s));
}
printf("Case %d: %d\n\n",++ks,ans);
}
return ;
}

UVA Live Archive 4490 Help Bubu(状压dp)的更多相关文章

  1. UVA 1412 Fund Management (预处理+状压dp)

    状压dp,每个状态可以表示为一个n元组,且上限为8,可以用一个九进制来表示状态.但是这样做用数组开不下,用map离散会T. 而实际上很多九进制数很多都是用不上的.因此类似uva 1601 Mornin ...

  2. 【UVa】Headmaster's Headache(状压dp)

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  3. 【UVA】11825 Hackers' Crackdown(状压dp)

    题目 传送门:QWQ 分析 $ n<= 16 $ 显然是状压 然后搞一搞(靠着蓝书yy一下) 代码 #include <bits/stdc++.h> using namespace ...

  4. uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

    题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪( ...

  5. UVa 10817 - Headmaster's Headache(状压DP)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  6. UVA Mega Man's Mission(状压dp)

    把消灭了那些机器人作为状态S,预处理出状态S下可以消灭的机器人,转移统计方案.方案数最多16!,要用64bit保存方案. #include<bits/stdc++.h> using nam ...

  7. UVa 11795 Mega Man's Mission (状压DP)

    题意:你最初只有一个武器,你需要按照一定的顺序消灭n个机器人(n<=16).每消灭一个机器人将会得到他的武器. 每个武器只能杀死特定的机器人.问可以消灭所有机器人的顺序方案总数. 析:dp[s] ...

  8. UVA - 10817 Headmaster's Headache (状压dp+记忆化搜索)

    题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所 ...

  9. 状压DP UVA 10817 Headmaster's Headache

    题目传送门 /* 题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少 状压DP:一看到数据那么小,肯定是状压了.这个状态不好想,dp[s1][s2]表示s ...

随机推荐

  1. jmeter - 函数:Random 随机函数的使用

    场景:在做接口测试时,比如说要求用户的手机号码不允许重复,那此时可以通过Random 随机函数来解决此问题: 1.在JMeter 工具中,选择{选项-函数助手对话框-} 函数助手中选择 Random ...

  2. CF447A DZY Loves Hash 模拟

    DZY has a hash table with p buckets, numbered from 0 to p - 1. He wants to insert n numbers, in the ...

  3. HDU1729 Stone Game

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1729 思路:理解错题目了,以为SG模板直接套就行了.后来队友说了那个ci是不断变化的.那么每次可以放的石头 ...

  4. 使用工具自动生成Linq类文件

    第一部:运行cmd. 执行命令 cd C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools 第二步:执行 ...

  5. HDU 6153 A Secret 套路,求解前缀在本串中出现的次数

    http://acm.hdu.edu.cn/showproblem.php?pid=6153 首先相当于翻转两个串,然后求s2前缀在s1中出现的次数. 这是一个套路啦 首先把两个串结合起来,中间加一个 ...

  6. 迅雷笔试题 (JAVA多线程)启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC

    题目:http://wenku.baidu.com/view/d66187aad1f34693daef3e8a.html 启动三个线程,分别打印A B C,现在写一个程序 循环打印ABCABCABC. ...

  7. 【PKI】PKI-中的几种证书的区别

    CA根证书:CA根证书是整个PKI系统的根证书. 管理根证书:根CA,二级CA,KMC都有管理根证书,用来在系统部署时签发本级的超级管理员和审计管理员. 站点证书:CA.RA要和用户走SSL通讯,需要 ...

  8. Java反射详解(Spring配置)

    1. 反射原理 a).运行时通过 Class c = Class.forName("com.hua.xx.DynTest")加载类文件 b).通过 DynTest t = c.ne ...

  9. xcrun -sdk 选择

    在将FFmpeg编译成IOS版的时候,接触到编译脚本的一段(删减了部分): for ARCH in $ARCHS do if [ "$ARCH" = "i386" ...

  10. 服务器端控件的"客户端"

    控件的服务端ID和客户端ID 比如一个ID为TextBox1的服务器端控件,在客户端访问该控件的DOM元素时 错误: var txtbox=document.getElementByID(" ...