uvaLive 4490 Help Bubu 帮助布布 等价转化+DP


等价转换:


从有n本书的书堆里面抽取k本书,再插入书堆里面,计算书的杂乱度

等价于

向空的书架上按给出的顺序放上n本书,再从中抽取k本书,然后插入书堆里面,计算书的杂乱度

等价于

向空的书架上按给出的顺序放上n-k本书,然后再放上k本书,想放哪放哪,计算书的杂乱度


显然第一阶段放n-k本书,就是一个简单的背包+集合动态规划。


对于每一本书,可以选也可以不选。


dp[ind][v][last][s]表示考虑了前面ind本书,其中有v本没有放进去,last表示最后一本的高度,s表示选取了哪些高度的

书。


第二阶段:


对于没有放进去的书,如果书架中已经有与之高度相同的书,那么放到那本书旁边,杂乱度不变。


如果没有,随便放,但要求:和它同高度没放进去的书要和它放在一起,杂乱度+1。



/**==========================================
 *   This is a solution for ACM/ICPC problem
 *
 *   @source:uvaLive 4490 - Help Bubu (Wuhan 2009)
 *   @type:  dp
 *   @author: wust_ysk
 *   @blog:  http://blog.csdn.net/yskyskyer123
 *   @email: 2530094312@qq.com
 *===========================================*/
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define REP(i,n)  for(int i=0 ;i<(n) ;i++)
#define ysk(x)  (1<<(x))
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int maxn= 100   ;

int n,V,all,kase=0;
int h[maxn+5];
const int N=8;
const int ed=ysk(N)-1;
int dp[2][N+2][maxn+5][ed+3];//[当前阶段][最后一个是谁][几个没选][选了哪些种];

int cal(int s)
{
    int ans=0;
    for(int i=0;i<N;i++) if(all&ysk(i))
    {
        int x=s&ysk(i);
        int y=all&ysk(i);
        ans+=  x^y?1:0;//我艹,当初写成了x^y,wa了好多发
    }
    return ans;
}

void update(int & ans ,int ret)
{
    if(ans<0||ret<ans)  ans=ret;
}
void work()
{

   memset(dp,-1,sizeof dp);
    int now=0,pre=1;

    dp[now][0][0][0]=0;
    for(int i=1;i<=n;i++)
    {
        now^=1;
        pre^=1;
        for(int last=0;last<=N;last++) if(!last || all&ysk(last-1)) //最后一个是谁
        {
            for(int v=0;v<=V;v++ )//几个没选
            {
                for(int s=0;s<=ed;s++)  if(~dp[pre][last][v][s])//选了哪些种
                {
                    int x=h[i]-25;

                    if(v+1<=V)
                    {
                        update(dp[now][last][v+1][s],dp[pre][last][v][s]  );
                    }

                    int ret= (last==x+1) ?dp[pre][last][v][s]:dp[pre][last][v][s]+1;
                    update( dp[now][x+1][v][s|ysk(x)],ret   );

                }
            }
        }

        memset(dp[pre],-1,sizeof dp[pre]);//

    }


    int ans=n;
    for(int last=0;last<=N;last++) if(!last || all&ysk(last-1))
    {
        for(int v=0;v<=V;v++)
        {
            for(int s=0;s<=ed;s++) if(~dp[now][last][v][s])
            {
                ans=min(ans,cal(s)+dp[now][last][v][s]);
            }
        }
    }
    printf("Case %d: %d\n\n",++kase,ans);


}
int main()
{
    while(~scanf("%d%d",&n,&V)&&(n||V))
    {
        all=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&h[i]);
            all|= ysk(h[i]-25);
        }
        work();

    }

   return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值