zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    2016计算机专业考研:c++大学教程第二版目录(下)
    2016考研计算机考研备考书籍推荐
    2014年计算机考研真题重点选择题部分真题及解析
    2016计算机考研:数据结构常用算法精析
    2015考研计算机专业基础综合试题真题及答案(1)
    java串讲之String 如何定义字符串对象
    WindowsService
    sql 将datetime类型转化为指定格式的字符串
    C# 利用SMTP异步发送邮件
    Visual Studio
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822447.html
Copyright © 2011-2022 走看看