动态规划专项intermediate:LA 4490

刚开始是用记忆化搜索做的,貌似是贪心出了问题,各种WA。后来搜了下AC的代码,清一色的递推。刚开始看不懂,可能是因为什么dp都用记忆化搜索做的,显然,递推更考验思维而且时间复杂度比记忆化搜索低,以后得多用递推做题啊。

找了一道写的相对简单的代码,看懂了之后写,还T了几炮……

大概思路就是4维dp,dp[i][j][k][p]表示进行到第i本书,移动了j本书,k是已经摆放了的书的高度的集合,p是最后一本书的高度,dp值为此时分块的最小数量。

每本书分两种情况,移动或不移动。这里需要贪心一下,就是当之前已经摆放了x高度的书时,如果再移动x高度的书时就不可能再增加分块的数量了。所以,最终的结果就是dp值再加上状态k中未出现的高度的个数。

最后2.7s+水过了……

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int inf=1e9;
int dp[110][110][1<<8][9];
int n,k,m;
int a[110],vis[10],two[20];
int min(int a,int b){return a>b?b:a;}
int main()
{
    int kase=1;
    two[0]=1;
    for(int i=1;i<=10;i++) two[i]=two[i-1]*2;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        if(!n&&!k) break;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]-=24;
            vis[a[i]]=1;
        }
        m=0;
        for(int i=1;i<=9;i++)
        {
            if(vis[i])
            {
                m++;
                for(int j=1;j<=n;j++) if(a[j]==i) a[j]=m;
            }
        }
        int cnt=(1<<m)-1;
        for(int i=0;i<=n;i++)
           for(int j=0;j<=k;j++)
              for(int p=0;p<=cnt;p++)
                 for(int q=0;q<=m;q++) dp[i][j][p][q]=inf;
        dp[0][0][0][0]=0;
        for(int i=0;i<n;i++)
           for(int j=0;j<=k;j++)
              for(int p=0;p<=cnt;p++)
                 for(int q=0;q<=m;q++) if(dp[i][j][p][q]!=inf)
                 {
                     dp[i+1][j][p|two[a[i+1]-1]][a[i+1]]=min(dp[i+1][j][p|two[a[i+1]-1]][a[i+1]],dp[i][j][p][q]+(q!=a[i+1]));
                     dp[i+1][j+1][p][q]=min(dp[i+1][j+1][p][q],dp[i][j][p][q]);
                 }
        int ans=inf;
        for(int i=0;i<=k;i++)
           for(int j=0;j<=cnt;j++)
              for(int p=0;p<=m;p++)
              {
                  int tmp=0;
                  for(int q=1;q<=m;q++) if((j&two[q-1])==0) tmp++;
                  ans=min(ans,dp[n][i][j][p]+tmp);
              }
        printf("Case %d: %d\n\n", kase++, ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值