hihoCoder第八周——状态压缩·一

hihoCoder第八周——状态压缩·一

题目链接:http://hihocoder.com/problemset/problem/1044

注意点

动态规划,状态压缩
1、best[i][j]表示在j决策的情况下,计算到第i个座位时可以清理的最多垃圾数。

2、解释下j决策:
因为考虑到计算i+1行的数据时(即清扫到i+1个座位时各种决策下的最大清理垃圾数),需要考虑如果清扫该座位的垃圾会不会造成纠纷(即连续的M个座位中有Q个以上的座位被清扫)。所以我们应该把清扫到第i个座位并取得最大清扫数时,该座位前的M个座位(包括第i个座位)是否清扫记录下来。用01串记录,比如:M=3,i=4,如果在清扫座位2,4时获得最大清扫数,此时决策j用01串表示就是101(从左到右依次表示:座位2清扫,座位3不清扫,座位4清扫),把101转化为5,所以得到best[4][5]。

3、如何计算best[i][j]
1)首先如果one_num(j)(决策j包含的1的个数)大于Q,best[i][j]=0
2)如果one_num(j)小于Q,那么座位 i 的决策 j 可能由座位 i-1 的决策 j/2 或者 j/2 + 1<<(M-1) 得来。而且j的最后一位为1,代表清扫第i个座位,j的最后一位为0,代表没清扫最后一个座位。所以best[i][j] = max(best[i-1][j/2],best[i-1][j/2 + (1<<(M-1)) )。若果j为奇数,best[i][j]还要再加上weight[i]。
3)如果one_num(j)等于Q时,与小于Q时一样

4、当然计算best第i行时只用到了第i-1行的数据,可以用2*(1《M)大小的二维数组。至于为什么不能像前面的例题一样用一维数组,是因为这里best[i][j] = max(best[i-1][j/2],best[i-1][j/2 + (1<<(M-1)) ),不能保证用于更新的数据(j/2,j/2+(1<<(M-1))都在待更新的数据(j)的一边。

可执行代码

#include<iostream>
#include<fstream>
#include<math.h>
using namespace std;
int ones(int j)
{
    int res = 0;
    while(j!=0)
    {
        res+=(j%2);
        j/=2;
    }
    return res;
}

int main()
{
    ifstream cin("input.txt");
    int N,M,Q;
    cin>>N>>M>>Q;

    //垃圾数
    int * weight = new int[N];
    for(int i =0;i<N;i++)
        cin>>weight[i];

    //动态数组best(i,j)表示在j决策下扫到第i个座位能清理的最多垃圾
    int ** best = new int*[N+1];
    int len = 1<<M;
    for(int i = 0;i<=N;i++)
    {
        best[i] = new int[len];
        //memset(best[i],0,len*sizeof(best[i]));
        for(int j = 0;j<len;j++)
            best[i][j] = 0;
    }

    for(int i = 0;i<N+1;i++)
    {
        for(int j = 0;j<len;j++)
            cout<<best[i][j]<<" ";
        cout<<endl;
    }


    for(int i = 0;i<N;i++)
    {
        for(int j =0;j<len;j+=2)
        {
            int one_num = ones(j);
            if(one_num>Q)
                best[i+1][j] = best[i+1][j+1] = 0;
            if(one_num<Q)
            {
                int temp;
                int a = j>>1;
                int b = a + (1<<(M-1));//j可由上一层的a和b转移过来
                temp = max(best[i][a],best[i][b]);
                best[i+1][j] = best[i+1][j+1] = temp;
                best[i+1][j+1] += weight[i];
            }
            if(one_num == Q)
            {
                int temp;
                int a = j>>1;
                int b = a + (1<<(M-1));//j可由上一层的a和b转移过来
                temp = max(best[i][a],best[i][b]);
                best[i+1][j] = temp;
                best[i+1][j+1] = 0;
            }
        }
    }
    test
    //for(int i = 0;i<=N;i++)
    //{
    //  for(int j = 0;j<len;j++)
    //      cout<<best[i][j]<<" ";
    //  cout<<endl;
    //}
    //输出最后一行的最大数
    int result = 0;
    for(int i = 0;i<len;i++)
        result = max(best[N][i],result);

    cout<<result;

    for(int i = 0;i<=N;i++)
        delete[] best[i];
    delete[] best;
    delete[] weight;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值