UVa12235: Help Bubu 题解

我们可以发现一个性质:对于所有我拿出来的数,如果剩下的数列里面还有这个数,那我可以放在它旁边,答案不变,否则就要全部放在数列最后面,答案+1
有了这个性质,我们考虑dp
dp[i][j][Mask][m]表示当前考虑到第i位,已经抽出了j本书,当前最后一本保留的书是m,Mask的第i位表示的是从1~i所有的i书是否被全部抽出了
转移的话,讨论第i+1本书取还是不取
最后,对于所有的dp[n][k][Mask][m],如果某种书被全部取出了,答案要+1

*我在转移的时候想蠢了,以为一定要枚举上一本抽出的书….太菜了

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=1e9+7;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;
const double pi=3.14159265;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,k;
int dp[101][101][260][9];
int a[148];bool exist[18];

int main ()
{
    int i,j,Mask,cur,toMask,ca=0;
    while (scanf("%d%d",&n,&k) && n && k)
    {
        memset(exist,false,sizeof(exist));
        for (i=1;i<=n;i++) a[i]=getint()-24,exist[a[i]]=true;
        for (i=0;i<=n;i++)
            for (j=0;j<=k;j++)
                for (Mask=0;Mask<=(1<<8)-1;Mask++)
                    for (cur=0;cur<=8;cur++)
                        dp[i][j][Mask][cur]=INF;
        dp[0][0][(1<<8)-1][0]=0;
        for (i=0;i<=n-1;i++)
            for (j=0;j<=k;j++)
                for (Mask=0;Mask<=(1<<8)-1;Mask++)
                    for (cur=0;cur<=8;cur++)
                        if (dp[i][j][Mask][cur]<INF)
                        {
                            //i+1 is chosen
                            if (j<k) dp[i+1][j+1][Mask][cur]=min(dp[i+1][j+1][Mask][cur],dp[i][j][Mask][cur]);
                            //i+1 isn't chosen
                            toMask=(Mask&(1<<(a[i+1]-1))?Mask^(1<<(a[i+1]-1)):Mask);
                            dp[i+1][j][toMask][a[i+1]]=min(dp[i+1][j][toMask][a[i+1]],dp[i][j][Mask][cur]+(a[i+1]!=cur));
                        }
        int ans=INF,curans;
        for (Mask=0;Mask<=(1<<8)-1;Mask++)
            for (cur=0;cur<=8;cur++)
                if (dp[n][k][Mask][cur]<INF)
                {
                    curans=dp[n][k][Mask][cur];
                    for (j=1;j<=8;j++)
                        if (exist[j] && Mask&(1<<(j-1))) curans++;
                    ans=min(ans,curans);
                }
        printf("Case %d: %d\n\n",++ca,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/iceprincess_1968/article/details/80025304