随笔-68  评论-10  文章-0  trackbacks-0
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=3237
用f[i,j,k,s]表示从前i本书中取出j本,没被取出书的状态为k(k不仅要表示书存在的种类,还要具体表示哪类书存在),没被取出书的最后一本高度为s时,剩下书的最小mess值。由于书按高度分类共有8类,可以用八位二进制来表示剩余书的状态,如果对应位为1则表明该类书存在。各类书存在与否,状态众多,这里可以进行状态压缩。 不考虑被拿出来的书的原因是,我们可以把这些书放到最恰当的位置,对前面求最优值不会产生影响。现在由前i-1本书推后面:对于第i本书,若要取f[i,j+1,k,s]=min{f[i,j+1,k,s],f[i-1,j,k,s]};若不取分两种情况:第i本书的高度与前面相同时,f[i,j,k,s]=min{f[i,j,k,s],f[i-1,j,k,s]};第i本书的高度与前面不同时,f[i,j,k|(1<<h[i]),h[i]]=min{f[i,j,k|(1<<h[i]),h[i]], f[i,j,k,s]+1}.   最后的答案为:min{f[n,j,k,s]+num(k)},num(k)={k^(书最初的状态)}这个二进制数中1的个数,表示被拿出来的书的种类数。见代码:
#include<iostream>
#define min(a,b) (a<b?a:b)
using namespace std;
const int inf=10000000;
int n,m,begin;
int h[105],num[1<<8];
int f[2][105][1<<8][9];
void Init()
{
     
int i,j;
     memset(num,
0,sizeof(num));
     
for(i=0;i<(1<<8);i++)
     
{
         
for(j=0;j<8;j++)
         
if(i&(1<<j)) num[i]++;
     }

}

int main()
{
    
int test=1;
    Init();
    
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
    
{
         
int i,j,k,s;
         begin
=0;
         
for(i=1;i<=n;i++)
         
{
             scanf(
"%d",&h[i]);
             h[i]
-=25;
             begin
=begin|(1<<h[i]);
         }

         
for(i=0;i<=m;i++)
         
for(j=0;j<(1<<8);j++)
         
for(k=0;k<=8;k++
         f[
0][i][j][k]=inf;
         
         f[
0][0][0][8]=0;
         
         
for(i=1;i<=n;i++)
         
{
              
for(j=0;j<=m;j++)
              
for(k=0;k<(1<<8);k++)
              
for(s=0;s<=8;s++)
              f[i
&1][j][k][s]=inf;
              
              
for(j=0;j<=i-1&&j<=m;j++)
              
for(k=0;k<(1<<8);k++)
              
for(s=0;s<=8;s++)
              
if(f[(i-1)&1][j][k][s]!=inf)
              
{
                   
if(j<m)f[i&1][j+1][k][s]=min(f[i&1][j+1][k][s],f[(i-1)&1][j][k][s]);
                   
                   
if(h[i]==s) f[i&1][j][k][s]=min(f[i&1][j][k][s],f[(i-1)&1][j][k][s]);
                   
else f[i&1][j][k|(1<<h[i])][h[i]]=min(f[i&1][j][k|(1<<h[i])][h[i]],f[(i-1)&1][j][k][s]+1);
              }

         }

         
int ans=inf;
         
for(i=0;i<=m;i++)
         
for(j=0;j<(1<<8);j++)
         
for(k=0;k<8;k++)
         
if(f[n&1][i][j][k]!=inf)
         
{
              
int temp=j^begin;
              
if(ans>f[n&1][i][j][k]+num[temp])
              ans
=f[n&1][i][j][k]+num[temp];
         }

         printf(
"Case %d: %d\n\n",test++,ans);
    }

    
//system("pause");
    return 0;
}

posted on 2010-08-23 10:56 wuxu 阅读(415) 评论(0)  编辑 收藏 引用 所属分类: 动态规划

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理