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 #include <iostream>
     2 #include <cstring>
     3 using namespace std;
     4 
     5 const int MAX_N = 1001;
     6 const int MAX_M = 10;
     7 
     8 int N, M, Q;
     9 int w[MAX_N];
    10 int dp[MAX_N][1<<MAX_M];
    11 bool ok[1<<MAX_M];
    12 
    13 void init() {
    14     memset(ok, false, sizeof(ok));
    15     int val, cnt;
    16     for (int i = 0; i < (1<<M); ++i) {
    17         val = i; cnt = 0;
    18         while (val > 0) {
    19             cnt += (val & 1);
    20             val >>= 1;
    21         }
    22         ok[i] = (cnt <= Q);
    23     }
    24 }
    25 
    26 void solve() {
    27     memset(dp, -1, sizeof(dp));
    28     memset(dp[0], 0, sizeof(dp[0]));
    29     for (int i = 1; i <= N; ++i) {
    30         for (int j = 0; j < (1<<M); ++j) if (dp[i-1][j] != -1) {
    31             int s0 = ((j<<1) & ((1<<M) - 1));
    32             int s1 = ((j<<1 | 1) & ((1<<M) - 1));
    33             dp[i][s0] = max(dp[i][s0], dp[i-1][j]);
    34             if (ok[s1]) {
    35                 dp[i][s1] = max(dp[i][s1], dp[i-1][j] + w[i]);
    36             }
    37         }
    38     }
    39     int res = 0;
    40     for (int i = 0; i < (1<<M); ++i) {
    41         res = max(res, dp[N][i]);
    42     }
    43     cout << res << endl;
    44 }
    45 
    46 int main() {
    47     while (cin >> N >> M >> Q) {
    48         init();
    49         for (int i = 1; i <= N; ++i) {
    50             cin >> w[i];
    51         }
    52         solve();
    53     }
    54     return 0;
    55 }
  • 相关阅读:
    leetcode(5)-罗马数字转整数
    leetcode(4)-整数反转
    leetcode(3)-回文数
    leetcode(2)-有效的括号
    leetcode(1)-两数之和
    HTTP基础(一)
    ubuntu 18.04安装MariaDB 10.04并通过远程navicat连接
    ubuntu18.04 root用户登录
    xshell连接ubuntu虚拟机
    ubuntu18.04使用node压缩包的安装及配置
  • 原文地址:https://www.cnblogs.com/easonliu/p/4422771.html
Copyright © 2011-2022 走看看