zoukankan      html  css  js  c++  java
  • HihoCoder 1044 垃圾清理 (优化:状态压缩)

    状态压缩·一

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市——那座城市即将举行美食节!

    但是不幸的是,小Hi和小Ho并没有能够买到很好的火车票——他们只能够乘坐最为破旧的火车进行他们的旅程。

    不仅如此,因为美食节的吸引,许多人纷纷踏上了和小Hi小Ho一样的旅程,于是有相当多的人遭遇到了和小Hi小Ho一样的情况——这导致这辆车上的人非常非常的多,以至于都没有足够的位置能让每一个人都有地方坐下来。

    小Hi和小Ho本着礼让他们的心情——当然还因为本来他们买的就是站票,老老实实的呆在两节车厢的结合处。他们本以为就能够这样安稳抵达目的地,但事与愿违,他们这节车厢的乘务员是一个强迫症,每隔一小会总是要清扫一次卫生,而时值深夜,大家都早已入睡,这种行为总是会惊醒一些人。而一旦相邻的一些乘客被惊醒了大多数的话,就会同乘务员吵起来,弄得大家都睡不好。

    将这一切看在眼里的小Hi与小Ho决定利用他们的算法知识,来帮助这个有着强迫症的乘务员——在不与乘客吵起来的前提下尽可能多的清扫垃圾。

    小Hi和小Ho所处的车厢可以被抽象成连成一列的N个位置,按顺序分别编号为1..N,每个位置上都有且仅有一名乘客在休息。同时每个位置上都有一些垃圾需要被清理,其中第i个位置的垃圾数量为Wi。乘务员可以选择其中一些位置进行清理,但是值得注意的是,一旦有编号连续的M个位置中有超过Q个的位置都在这一次清理中被选中的话(即这M个位置上的乘客有至少Q+1个被惊醒了),就会发生令人不愉快的口角。而小Hi和小Ho的任务是,计算选择哪些位置进行清理,在不发生口角的情况下,清扫尽可能多的垃圾。

    输入

    每个测试点(输入文件)有且仅有一组测试数据。

    每组测试数据的第一行为三个正整数N、M和Q,意义如前文所述。

    每组测试数据的第二行为N个整数,分别为W1到WN,代表每一个位置上的垃圾数目。

    对于100%的数据,满足N<=1000, 2<=M<=10,1<=Q<=M, Wi<=100

    输出

    对于每组测试数据,输出一个整数Ans,表示在不发生口角的情况下,乘务员最多可以清扫的垃圾数目。

    样例输入
    5 2 1
    36 9 80 69 85 
    样例输出
    201

    1:我想的是开dp[1010][10][10],dp[n][m][q]表示以n为结尾的m的位置中选q个的结果,然后扫一遍得到ans。对于m中选的哪q个不管

    后面发现正是这个不管导致  ans<=standard_ans。

    因为不知道之间应该选多少个,所以也不知道ans从哪里转移过来。

         for(i=1;i<=n;i++){
            for(j=1;j<=min(i,m);j++)
               for(k=0;k<=min(j,q);k++){
                   dp[i][j][k]=max(dp[i][j][k],dp[i][j][k-1]);
                   dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k]);
                   if(k>0)dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k-1]+w[i]);
                   ans[i]=max(ans[i],ans[i-1]);
                   ans[i]=max(ans[i],dp[i][j][k]+(i>=m?ans[i-m]:0));
               }
         }

    2:记录小区间具体选了哪些,用dp[1010][1<<m] 来明确到哪一个。过程是从前向后推。

         int ch=(1<<m)-1; 
         for(int i=1;i<=n;i++){
            for(int j=0;j<(1<<m);j++){
                int s0=(j<<1)&ch ;
                int s1=((j<<1)|1)&ch ;
                dp[i][s0]=max(dp[i-1][j],dp[i][s0]);//第i位不选
                if(ok[s1]) dp[i][s1]=max(dp[i-1][j]+w[i],dp[i][s1]) ;//第i位选
            }
         } 

    3,check预处理1<<m种排列

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define maxn 1024 
    int dp[1010][maxn] ;
    int ok[maxn] ;
    int w[1010];
    void check(int m , int q)
    {
        for(int i=0;i<(1<<m);i++){
            int cnt=0,tmp=i ;
            while(tmp){
                if(tmp&1) cnt++;
                tmp>>=1;
            }
            ok[i]=(cnt<=q);
        }
    }
    int main()
    {
         int i,j,n,m,q ;
         scanf("%d%d%d",&n,&m,&q);
         for(int i=1;i<=n;i++) scanf("%d",w + i) ;
         check(m,q);
         int ch=(1<<m)-1; 
         for(int i=1;i<=n;i++){
            for(int j=0;j<(1<<m);j++){
                int s0=(j<<1)&ch ;
                int s1=((j<<1)|1)&ch ;
                dp[i][s0]=max(dp[i-1][j],dp[i][s0]);
                if(ok[s1]) dp[i][s1]=max(dp[i-1][j]+w[i],dp[i][s1]) ;
            }
         } 
        int ans=0 ;
        for(int j=0;j<(1<<m);j++) ans=max(ans,dp[n][j]);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    windows中dos命令指南
    HDU 2084 数塔 (dp)
    HDU 1176 免费馅饼 (dp)
    HDU 1004 Let the Balloon Rise (map)
    变态杀人狂 (数学)
    HDU 2717 Catch That Cow (深搜)
    HDU 1234 开门人和关门人 (模拟)
    HDU 1070 Milk (模拟)
    HDU 1175 连连看 (深搜+剪枝)
    HDU 1159 Common Subsequence (dp)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7782828.html
Copyright © 2011-2022 走看看