uvalive4490(状态压缩 + dp)
2016-04-26 22:21
375 查看
题目大意:
从左到右给出n本数的高度和最多可以抽取的书本的数量k,如果书本与相邻的书本的高度不相同的话就是一个段,段越多混乱度就越高。求最低的混乱度。
思路:
dp[i][j][s][end]表示前i本书操作了j次,剩下的书的状态为s,最后一本书是end的最低的混乱度。
那么对于一本书有两种情况:
1. 跟其前面的书籍的高度是一样的
那么dp[i][j][s][end] = min(dp[i][j][s][end],dp[i - 1][j][s][end]);
2. 跟其前面的书籍的高度是不一样
(1)抽取这本书出来
那么dp[i][j + 1][s][end] = min(dp[i][j + 1][s][end],dp[i - 1][j][s][end]);
为什么会等于dp[i - 1][j][s][end]?
因为你将第i本数抽取出来了实行了j + 1次操作相当于你对第i - 1本书实行了j次操作。
(2)不抽取这本书
那么dp[i][j][s | (1 << num)][num] = min(dp[i][j][s|(1 << num)][num],dp[i][j][s][end] + 1);
代码:
从左到右给出n本数的高度和最多可以抽取的书本的数量k,如果书本与相邻的书本的高度不相同的话就是一个段,段越多混乱度就越高。求最低的混乱度。
思路:
dp[i][j][s][end]表示前i本书操作了j次,剩下的书的状态为s,最后一本书是end的最低的混乱度。
那么对于一本书有两种情况:
1. 跟其前面的书籍的高度是一样的
那么dp[i][j][s][end] = min(dp[i][j][s][end],dp[i - 1][j][s][end]);
2. 跟其前面的书籍的高度是不一样
(1)抽取这本书出来
那么dp[i][j + 1][s][end] = min(dp[i][j + 1][s][end],dp[i - 1][j][s][end]);
为什么会等于dp[i - 1][j][s][end]?
因为你将第i本数抽取出来了实行了j + 1次操作相当于你对第i - 1本书实行了j次操作。
(2)不抽取这本书
那么dp[i][j][s | (1 << num)][num] = min(dp[i][j][s|(1 << num)][num],dp[i][j][s][end] + 1);
代码:
#include <iostream> using namespace std; #include <cstring> #include <stdio.h> const int maxn = 1 << 8; const int INF = 0x3f3f3f3f; const int maxm = 110; int dp[2][maxm][maxn][10],n,k;//由于只有前后操作所以2就足够了 利用滚动数组 int rec[1 << 8]; void init() { for(int i = 0; i < (1 << 8); i++) {//记录每个状态的书本最多有多少种段数 主要是用于抽取出来的书籍重新插入 每插入一次就增加一个段 如果留下来的有这种类就不用增加 rec[i] = 0; for(int j = 0; j < 8; j++) if(i &(1 << j)) rec[i]++; } } int main() { int T = 0; init(); while(scanf("%d %d",&n,&k) == 2 &&n && k) { int S = 0; int num,now,pre; memset(dp[0],INF,sizeof(dp[0])); for(int i = 0; i < n; i++) { scanf("%d",&num); num -= 25; pre = i & 1;//滚动数组的巧妙用法 只需要考虑前后的时候可以使用 now = !pre; memset(dp[now],INF,sizeof(dp[now])); dp[now][i][(1 << num)][num] = 1; for(int j = 0; j <= min(i,k); j++) for(int s = S;s;s = (s - 1) & S) { for(int end = 0;(1 << end) <= s; end ++) { if(dp[pre][j][s][end] == INF) continue; if(end == num) dp[now][j][s][end] = min(dp[now][j][s][end],dp[pre][j][s][end]); else { dp[now][j + 1][s][end] = min(dp[now][j + 1][s][end],dp[pre][j][s][end]); dp[now][j][s |(1 << num)][num] = min(dp[now][j][s |(1 << num)][num],dp[pre][j][s][end] + 1); } } } S = S |(1 << num);//记录下总的种类数 } int ans = INF; for(int j = 0; j <= k; j++) { for(int s = S;s;s = (s - 1)&S) { for(int end = 0;(1 << end) <= s;end++) { if(dp[n & 1][j][s][end] != INF ){ ans = min(ans,dp[n & 1][j][s][end] + rec[S^s]);//S^s记录的是被抽出来的在留下的种类中不存在的种类 //cout << ans <<endl; } } } } printf("Case %d: %d\n\n",++T,ans); } return 0; }
相关文章推荐
- spring4.x注解概述
- mybatis 返回类型为HashMap 字段为空
- Android项目部署时,发生AndroidRuntime:android.view.InflateException: Binary XML file line #168: Error inflating class错误
- hdoj2006(java)求奇数的乘积
- 亚马逊AWS免费套餐EC2安装centos连接登录并创建root
- 仿Google应用动态隐藏显示状态栏
- 练习005
- c# 匿名方法
- [Lintcode]Valid Parentheses
- [置顶] PLSQL Developer连接数据库报错ora-12514解决
- poj2886Who Gets the Most Candies?
- Android APP头像的图标与背景的设置
- Linux 0.11几个重要的切换
- ValueAnimator的使用
- KindEditor编辑器的使用
- 338. Counting Bits
- MySQL 5.7.6 以上版本的 root 密码重置
- 致敬——C语言
- php安装解析
- ZOJ_1122