hihoCoder第八周状态压缩1

来源:互联网 发布:手机pdf制作软件 编辑:程序博客网 时间:2024/05/22 03:28

    • 题目
      • 解法

题目:

有N个数,编号为1……N。其中第i个数对应的值为Wi。在其中选取一些数,使选取的这些数的和最大。

选取规则为:编号连续的M个位置中,不能有超过Q个数被选中(不包括Q)。

输入

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

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

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

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

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

5 2 136 9 80 69 85 

样例输出

201

解法

(代码提交后,还是WA,还不知错在哪)
这其实也是一道动态规划题目,需要找到状态转移方程。像求解背包问题那样,设一个best(i)表示前i个数组中已经做出选择的最大和;但是这样没法求解best(i+1),因为best(i)并没有表明[i-M+1……,i-1,i]是怎么选择的,所以无法求解best(i+1),因此我们在求解best(i)的同时还要记录这一步做出了那些选择。可以设一个best(i,p1,p2,……,pM-1)表示当前已经决定编号为1……i的位置,且(i-j+1)位置是否选取用pj记录(0表示不选取,1表示选取),这时前i个已选取位置的最大值。那么状态转移方程为

best(i,p1,p2,,pM1)+wi>best(i+1,p1,p2,,pM2),j=1M1<Q

best(i,p1,p2,,pM1)>best(i+1,0,p2,,pM2)

这个状态方程不方便编程表示,p1,p2,,pM1的值为0或1,那么可以用一个长度为M1的二进制数表示。状态转移方程为:
best(i,s)+wi+1>best(i+1,s2+2M1),s2Q

best(i,s)>best(i+1,s2)

写代码测试:

#include <iostream>int best[1001][1 << 10 + 1];int w[1001];unsigned int CountBit(unsigned int n){    unsigned int count = 0;    while (n)    {        if (n&1)            ++count;        n = n >> 1;    }    return count;}inline int max(int a, int b){    return a > b ? a : b;}int main(){    int N, M, Q;    std::cin >> N >> M >> Q;    for (int i = 1; i <= N; ++i)        std::cin >> w[i];    int maxJ = 1 << M - 1;    for (int i = 1; i <= N; ++i)    {        for (int j = 0; j < maxJ; ++j)        {            if (CountBit(j) <= Q)            {                best[i][j] = max(best[i - 1][j / 2], best[i - 1][j / 2 + 1 << (M - 1)])+(j&1)*w[i];            }        }    }    int result = 0;    for (int j = 0; j<maxJ; ++j)        result = max(result, best[N][j]);    std::cout << result << std::endl;}

可以看出,在计算i行是,只用到了i-1行。0……(i-1)行都没用到,所以只需要开辟了两行的二维数组即可。

#include <iostream>int best[2][1025];int w[1001];unsigned int CountBit(unsigned int n){    unsigned int count = 0;    while (n)    {        if (n & 1)            ++count;        n = n >> 1;    }    return count;}inline int max(int a, int b){    return a > b ? a : b;}int main(){    int N, M, Q;    std::cin >> N >> M >> Q;    for (int i = 1; i <= N; ++i)        std::cin >> w[i];    int maxJ = (1 << M) ;    for (int i = 1; i <= N; ++i)    {        for (int j = 0; j < maxJ; ++j)        {            if (CountBit(j) <= Q)            {                best[i & 1][j] = max(best[~i & 1][j / 2], best[~i & 1][j / 2 + 1 << (M - 1)]) + (j & 1)*w[i];            }        }    }    int result = 0;    for (int j = 0; j<maxJ; ++j)        result = max(result, best[N&1][j]);    std::cout << result << std::endl;}
0 1
原创粉丝点击