您的位置:首页 > 其它

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堆的情况。这样就可以自底向上求解了。

注意枚举状态时候的边界条件。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: