NOI 97 积木游戏
2015-07-21 19:37
435 查看
题目点我
lrj黑书上讲解动态规划的例题,通过多阶段决策思想来建立状态转移方程。
状态定义dp(i,a,b,k)dp(i, a, b, k)表示当前已经有ii堆,已经考虑过aa个方块(由于考虑的顺序,最后一次考虑的方块编号为aa),当前堆最顶上的方块编号为bb,并且这个方块的摆放方式为k(k=0,1,2k =0, 1, 2),由此状态(i,a,b,k)(i,a,b,k)到决策结束可以达到的高度最大值为dp(i,a,b,k)dp(i,a,b,k)
从状态(i,a,b,k)(i,a,b,k)开始,考虑下一个方块a+1a+1时,有三种可行的决策:
1. 把方块放到当前堆上,对应的后继状态是(i,a+1,a+1,k′)(i, a+1, a+1, k')且a+1a+1按照方式k′k'摆放时可以放到方块bb按方式kk摆放的平面上。状态转移方程为
dp(i,a+1,a+1,k′)=dp(i,a,b,k)+height(a+1,k′)dp(i, a+1, a+1, k')=dp(i,a,b,k) + height(a+1, k')
2. 这个方块另起一堆,对应后继状态(i+1,a+1,a+1,k′)(i+1, a+1, a+1, k'),且i<Mi < M,MM为总堆数。状态转移方程为
dp(i+1,a+1,a+1,k′)=dp(i,a,b,k)+height(a+1,k′)dp(i+1, a+1, a+1, k')=dp(i,a,b,k)+height(a+1, k')
3. 丢掉这个方块, 对应后继状态(i,a+1,b,k)(i, a+1, b, k),状态转移方程
dp(i,a+1,b,k)=dp(i,a,b,k)dp(i, a+1, b, k)=dp(i, a, b, k)
再加上边界条件,dp(1,i,i,k′)=height(i,k′)dp(1, i, i, k')=height(i, k'),即只有1块积木组成1堆的情况。这样就可以自底向上求解了。
注意枚举状态时候的边界条件。
lrj黑书上讲解动态规划的例题,通过多阶段决策思想来建立状态转移方程。
状态定义dp(i,a,b,k)dp(i, a, b, k)表示当前已经有ii堆,已经考虑过aa个方块(由于考虑的顺序,最后一次考虑的方块编号为aa),当前堆最顶上的方块编号为bb,并且这个方块的摆放方式为k(k=0,1,2k =0, 1, 2),由此状态(i,a,b,k)(i,a,b,k)到决策结束可以达到的高度最大值为dp(i,a,b,k)dp(i,a,b,k)
从状态(i,a,b,k)(i,a,b,k)开始,考虑下一个方块a+1a+1时,有三种可行的决策:
1. 把方块放到当前堆上,对应的后继状态是(i,a+1,a+1,k′)(i, a+1, a+1, k')且a+1a+1按照方式k′k'摆放时可以放到方块bb按方式kk摆放的平面上。状态转移方程为
dp(i,a+1,a+1,k′)=dp(i,a,b,k)+height(a+1,k′)dp(i, a+1, a+1, k')=dp(i,a,b,k) + height(a+1, k')
2. 这个方块另起一堆,对应后继状态(i+1,a+1,a+1,k′)(i+1, a+1, a+1, k'),且i<Mi < M,MM为总堆数。状态转移方程为
dp(i+1,a+1,a+1,k′)=dp(i,a,b,k)+height(a+1,k′)dp(i+1, a+1, a+1, k')=dp(i,a,b,k)+height(a+1, k')
3. 丢掉这个方块, 对应后继状态(i,a+1,b,k)(i, a+1, b, k),状态转移方程
dp(i,a+1,b,k)=dp(i,a,b,k)dp(i, a+1, b, k)=dp(i, a, b, k)
再加上边界条件,dp(1,i,i,k′)=height(i,k′)dp(1, i, i, k')=height(i, k'),即只有1块积木组成1堆的情况。这样就可以自底向上求解了。
注意枚举状态时候的边界条件。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 105 int dp[MAX][MAX][MAX][3]; // i, a, b, k struct cube{ int len[3]; }cubes[MAX]; int max(int a, int b){ return a > b ? a : b; } int judge(int upper, int k1, int lower, int k2){ // k : 0, 1, 2 if( (cubes[upper].len[(k1+1)%3] <= cubes[lower].len[(k2+1)%3] && cubes[upper].len[(k1+2)%3] <= cubes[lower].len[(k2+2)%3]) || (cubes[upper].len[(k1+2)%3] <= cubes[lower].len[(k2+1)%3] && cubes[upper].len[(k1+1)%3] <= cubes[lower].len[(k2+2)%3])){ return cubes[upper].len[k1]; } return 0; } int solve(int N, int M){ for(int a = 0; a < N-1; a++){ for(int i = 1; i <= a+1; i++){ for(int b = i-1; b <= a; b++){ for(int k = 0; k < 3; k++){ //current pile: for(int k2 = 0; k2 < 3; k2++){ if(0 != judge(a+1, k, b, k2)) dp[i][a+1][a+1][k] = max(dp[i][a+1][a+1][k], judge(a+1, k, b, k2) + dp[i][a][b][k2]); } //new pile: if(i < M){ for(int k2 = 0; k2 < 3; k2++) dp[i+1][a+1][a+1][k] = max(dp[i+1][a+1][a+1][k], cubes[a+1].len[k] + dp[i][a][b][k2]); } //ignore: dp[i][a+1][b][k] = max(dp[i][a+1][b][k], dp[i][a][b][k]); } } } } int result = 0; for(int b = M - 1; b < N; b++) for(int k = 0; k < 3; k++) result = max(result, dp[M][N-1][b][k]); return result; } int main(){ int N, M; while(EOF != scanf("%d %d", &N, &M)){ memset(dp, 0, sizeof(int) * 3 * MAX * MAX * MAX); for(int i = 0; i < N; i++){ scanf("%d %d %d", &cubes[i].len[0], &cubes[i].len[1], &cubes[i].len[2]); for(int k = 0; k < 3; k++) dp[1][i][i][k] = cubes[i].len[k]; } int result = solve(N, M); printf("%d\n", result); } return 0; }
相关文章推荐
- 工作常用英语单词
- Android Application详解
- ANDROID开发中注意不同手机CPU架构对SO文件的不同需求。
- 剑指offer-面试题8.旋转数组的最小数字
- STL LIST链表的使用 C++
- HDU 1143
- hdu3076ssworld VS DDD 概率dp
- 语法分器析总结
- Makefile -fPIC 选项
- GIT仓库恢复
- Mac价格对比
- hdu 1717 小数化分数2
- Storm Trident Example 代码阅读笔记
- Mysql数据库笔记
- ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)
- Ubuntu mysql 中文,启动,重启,远程连接相关问题
- 简单文件操作(库函数)
- poj 3254
- windows下安装php5.5的redis扩展
- java定时任务spring+quartz作业调度