Help Bubu UVALive

传送门

题目大意

有n本书,最多k次操作,每次操作可以把一本书拿出来,放到一个位置去,有一个指标较mess度,他是书的高度的段数,连续的书高度一样算一段,现在给你最先开始各个位置上的书的高度,求操作后最小的mess度。

分析

首先我们要注意一个非常非常重要的条件就是书的高度的范围很小。所以我们不由想到了状压dp。我们再仔细思考一下不难想到dp[i][j][msk][k]表示考虑到第i本,挪动了j次,没挪动的书的高度集合为msk,没挪动的书的最后一本高度为k。然后我们便可以转移(具体见代码),而最后答案要将dp值加上对于所有高度为h的书都挪动了的不同h的数量。注意数组不要开小啦。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define gm(x,y) x=min(x,y)
const int inf = 0x3f3f3f3f;
int n,m,sum,dp[2][105][260][10],apr[50],c[105],cse,now;
inline void init(){
      memset(apr,0,sizeof(apr));
      sum=0;
      cse++;
}
inline void deal(int pl,int x){
        if(!apr[x]){
            sum++;
            apr[x]=sum;
        }
        c[pl]=apr[x];
        return;
}
inline int Sum(int msk){
      int res=0;
      for(int i=0;i<sum;i++)
        if(((1<<i)&msk)==0)
          res++;
      return res;
}
inline void DP(){
      int i,j,k,s;
      now=1;
      memset(dp[1],0x3f,sizeof(dp[1]));
      dp[1][0][(1<<(c[1]-1))][c[1]]=1;
      dp[1][1][0][0]=0;
      for(i=1;i<n;i++){
        now^=1;
        memset(dp[now],0x3f,sizeof(dp[now]));
        for(j=0;j<=m;j++)
          for(s=0;s<(1<<sum);s++)
            for(k=0;k<=sum;k++)if(dp[now^1][j][s][k]<inf){
              //cout<<i<<' '<<j<<' '<<s<<' '<<k<<' '<<dp[now^1][j][s][k]<<endl;
              if(k==c[i+1])
                gm(dp[now][j][s][k],dp[now^1][j][s][k]);
               else 
                gm(dp[now][j][s|(1<<(c[i+1]-1))][c[i+1]],dp[now^1][j][s][k]+1);
              if(j<m)gm(dp[now][j+1][s][k],dp[now^1][j][s][k]);
            }
      }
      return;
}
inline void getans(){
      int ans=inf,i,j,k;
      for(i=0;i<=m;i++)
        for(j=0;j<(1<<sum);j++)
          for(k=1;k<=sum;k++)
            gm(ans,dp[now][i][j][k]+Sum(j));
      printf("Case %d: %d

",cse,ans);
}
int main(){
      int i,j,k;
      cse=0;
      scanf("%d%d",&n,&m);
      while(n&&m){
          init();
          for(i=1;i<=n;i++){
            scanf("%d",&c[i]);
            deal(i,c[i]);
          }
          DP();
          getans();
          scanf("%d%d",&n,&m);
      }
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9483808.html