P1777 帮助 [状压dp]

帮助

题目描述见链接 .


color{red}{正解部分}

提出的书可以放在任意位置, 所以可以先放在一边, 到最后处理,

F[i,j,k,s]F[i, j, k, s] 表示处理到第 ii 本书, 提出了 jj 本书, 书架上最后一本书 高度kk, 书架上的书高度状态为 ss 时的 混乱值,
则决策有两个,

  • ii 提出, F[i,j,k,s]=min(F[i1,j1,k,s])F[i, j, k, s] = min(F[i-1, j-1, k, s])
  • 不将 ii 提出, F[i,j,k,s]=min(F[i1,j,p,s(1<<hi1)]+[pk],F[i1,j,p,s]+[pk])F[i, j, k, s] = min(F[i-1, j, p, s igoplus (1<<h_i-1)] + [p ot= k], color{red}F[i-1, j, p, s] + [p ot= k]) .

再考虑统计答案, Answer=min(F[N,0K,k,s]+cnt[sU])Answer = min(F[N, 0 ightarrow K, k, s] + cnt[s igoplus U]) .

其中 cnt[x]cnt[x] 表示 xx 二进制中 11 的个数 .

按以上方式更新状态时间复杂度 O(N2K228)O(N^2K^22^8), 但若使用状态去更新状态, 时间复杂度 O(N2K28)O(N^2K2^8) .


color{red}{实现部分}

  • 注意 ss 要开 256256 .
#include<bits/stdc++.h>
#define reg register

const int maxn = 105;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

int N;
int K;
int num;
int Test_cnt;
int h[maxn];
int Mp[maxn];
int cnt[260];
int F[maxn][maxn][10][260];

int main(){
        for(reg int i = 1; i < 260; i ++) cnt[i] = cnt[i ^ (i & -i)] + 1;
        while((N = read()) && (K = read())){ 
                memset(Mp, 0, sizeof Mp); num = 0;
                for(reg int i = 1; i <= N; i ++){ 
                        h[i] = read()-24;
                        if(!Mp[h[i]]) Mp[h[i]] = ++ num;
                        h[i] = Mp[h[i]];
                }
                for(reg int i = 0; i <= N; i ++)
                        for(reg int j = 0; j <= K; j ++)
                                for(reg int k = 0; k <= num; k ++)
                                        for(reg int s = 0; s < (1<<num); s ++) F[i][j][k][s] = 0x3f3f3f3f;
                F[0][0][0][0] = 0;
                for(reg int i = 1; i <= N; i ++)
                        for(reg int j = 0; j <= K; j ++)
                                for(reg int k = 0; k <= num; k ++)
                                        for(reg int s = 0; s < (1<<num); s ++){
                                                if(j >= 1) F[i][j][k][s] = std::min(F[i][j][k][s], F[i-1][j-1][k][s]);
                                                if((s & (1<<h[i]-1)) && k == h[i]){
                                                        int &t = F[i][j][k][s];
                                                        for(reg int p = 0; p <= num; p ++){
                                                                t = std::min(t, F[i-1][j][p][s] + (p != k));
                                                                t = std::min(t, F[i-1][j][p][s ^ (1<<k-1)] + (p != k));
                                                        }
                                                }
                                        }
                int Ans = N, U = (1<<num)-1;
                for(reg int j = 0; j <= K; j ++)
                        for(reg int i = 0; i <= num; i ++)
                                for(reg int s = 0; s < (1<<num); s ++) Ans = std::min(Ans, F[N][j][i][s] + cnt[s ^ U]);
                printf("Case %d: %d

", ++ Test_cnt, Ans);
        }
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822447.html