题意:书架上有n本书,连续的相同高度的归为一类,现在你最多可以拿走m本书然后可以放在任何位置,求最少的类
思路:看了别人的觉得学到了很多,首先dp[i][j][k][s]表示前i本书拿走j本剩下的书的状态是k最后一本书的高度是s的最少类数,其实当我们在不超过m次的拿书的过程中,如果能让类数达到最少的话,且拿走的书也固定了类数,那么就能求出最小了,觉得第4维的设定很精彩啊,一下子就为状态转移方程提供了思路,每次的书我们有拿与不拿的选择,那么当不拿走的时候如果这本书与目前的最后一本不一样的话就+1,否则不用,同时不断的滚动数组求出最小值,显然后三维就可以解释状态了,缺的是当前和上一步,又加了一维,
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int MAXN = 110;
const int INF = 0x3f3f3f3f;
int n,m,ht[MAXN],ans,one[1<<8];
int state,dp[2][MAXN][1<<8][10];
void init(){
for (int i = 0; i < (1<<8); i++){
for (int j = 0; j < 8; j++)
if (i & (1<<j))
one[i]++;
}
}
int main(){
int cas = 0;
init();
while (scanf("%d%d",&n,&m) != EOF && n+m){
int mx = state = 0;
for (int i = 1; i <= n; i++){
scanf("%d",&ht[i]);
ht[i] -= 25;
if (ht[i] > mx)
mx = ht[i];
state |= (1<<ht[i]);
}
++mx;
int tot = (1<<mx);
for (int j = 0; j <= m; j++)
for (int k = 0; k < tot; k++)
for (int s = 0; s <= mx; s++)
dp[1][j][k][s] = INF;
dp[1][0][1<<ht[1]][ht[1]] = 1;
dp[1][1][0][mx] = 0;
for (int i = 2; i <= n; i++){
int cur = i & 1;
int pre = 1 - cur;
for (int j = 0; j <= m; j++)
for (int k = 0; k < tot; k++)
for (int s = 0; s <= mx; s++)
dp[cur][j][k][s] = INF;
for (int j = 0; j <= m && j < i; j++)
for (int k = 0; k < tot; k++)
for (int s = 0; s <= mx; s++){
if (dp[pre][j][k][s] == INF)
continue;
int stk = k | (1<<ht[i]);
if (j < m)
dp[cur][j+1][k][s] = min(dp[cur][j+1][k][s],dp[pre][j][k][s]);
if (s == ht[i])
dp[cur][j][k][s] = min(dp[cur][j][k][s],dp[pre][j][k][s]);
else dp[cur][j][stk][ht[i]] = min(dp[cur][j][stk][ht[i]],dp[pre][j][k][s]+1);
}
}
int cur = n&1;
int ans = n;
for (int j = 0; j <= m; j++)
for (int k = 0; k < tot; ++k)
for (int s = 0; s < mx; s++)
if (dp[cur][j][k][s] != INF){
int st = state ^ k; //抽走的就是额外的类
ans = min(ans,one[st]+dp[cur][j][k][s]);
}
printf("Case %d: %d\n\n",++cas,ans);
}
return 0;
}
本文探讨了在有限拿书次数下,如何从书架上选取书籍以减少类别的数量,详细介绍了动态规划方法和状态转移方程的应用。
896

被折叠的 条评论
为什么被折叠?



