hihoCoder第八周状态压缩1

    • 题目
      • 解法

题目:

有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 1
36 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;
}

你可能感兴趣的:(动态规划,hihoCoder)