• [DP] Light Oj 1017 Brush(III)


    题目为 light oj 1017.

    现在是凌晨两点二十分,我却毫无睡意,这题折腾了我一个晚上,一直没有做对,最后发现转移方程忽略了一个重要的条件,泪奔~。

    干脆不睡觉,写一篇题解警醒自己,也算是对于自己考虑问题智障的惩罚。

    我真是个智障 0 s 0 .....

    题目大意是 , 给你N个二维坐标上的点 (x,y) , 每一个点代表一个污渍,现在有一把宽度为 W 的刷子,平行于 x 轴移动 K 次,问,最多能擦掉多少污渍。

    很明显这题和x坐标一点关系都没有(因为刷子沿着平行x轴移动,并可以移动无限远),分析y坐标就OK。 于是纪录y坐标以后排序,假设数组是 point[1...n]。直接DP因为点范围太大的缘故没有办法,所以先进行离散化,decode[1...len] 存放离散化以后的点的y轴坐标。 OK,然后就是很容易想到的转移情况。

    哈哈哈哈哈哈哈,简直欣喜若狂有没有,有没有! 居然如此有思路,难得难得。。。。

    dp[i][j] 表示,我擦完第i次以后,擦过decode[1...j](包含j) 这些污渍以后的最大擦去的数目,注意不一定是擦掉了所有的污渍(后面我就错在这里!!! T ^ T)

    转移方程很明显,对于每一种情况j,考虑为擦除的“上界” 那么下界就是 pre = lower_bound(decode,decode + len,decode[j] - W); 转移的情况就是

    dp[i][j] = max(dp[i][j] , dp[i - 1][pre - 1] + sum); (pre - 1 >= 0)

    dp[i][j] = max(dp[i][j] , sum);   (pre - 1 < 0)

    因为用了lower_bound 函数,所以如果搜索的这个值小于decode的最小值的话,就会是0,pre - 1失去意义,所以分类下。

    这里的sum很明显就是上下界(包含上下界)里的所有的污渍了。

    那么上界的位置在 

    upper_bound(point , point + n , decode[j]) - point;

    下界位置在

    lower_bound(point , point + n , decode[j] - w) - point;

    sum = 上界 - 下界;

    然后!!!

    然后!!!!

    是不是好像就OK了!!

    但是......

    但是老娘的AC呢!!!!

    并不是,痛苦的WA开始了,不停的错错错错错错错,想要撞死电脑有没有,有没有........

    我靠这还有什么情况啊~。

    不做出来就不睡觉了。。。。

    老娘和你没完!!!

    终于在凌晨一点半左右开窍了。

    发现了转移方程的纰漏,如果清理污渍的时候分成了两段,中间有污渍“不选”的时候会产生最优解,那么转移的时候就会错误。

    什么意思呢,也就是说,我们的方程dp[i][j] 表示的是清理了i次以后,高度为j污渍以下的污渍都已经考虑过了,这以后的最大值,才有转移的意义。

    就是说 dp[i][j] = max{dp[i][1....j]}

    所以在每一次转移完 dp[i][j] 以后,需要看看这个dp[i][j] 是不是当前 i , j 的最优解,也就是加上一句。

    dp[i][j] = max(dp[i][j] , dp[i][j - 1]);

    万一 dp[i][j - 1] 更好呢? 万一 高度为j 的污渍我不要,清理的能更多呢?

    终于对了!

    老娘终于可以睡觉了!!!

    卧槽,三点了。。。。。。 Orz ........

    代码君:

     1 /*
     2  
     3  light oj 1017
     4  
     5  */
     6 
     7 
     8 #include <iostream>
     9 #include <cstdio>
    10 #include <cstring>
    11 #include <algorithm>
    12 using namespace std;
    13 int point[110];
    14 int decode[110];
    15 int dp[110][110];
    16 int _decode(int n){
    17     int p = 1;
    18     int pre = point[0];
    19     decode[0] = point[0];
    20     for (int i = 1; i < n; i++) {
    21         if(pre == point[i]) continue;
    22         decode[p++] = point[i];
    23         pre = point[i];
    24     }
    25     return p;
    26 }
    27 int main(){
    28     int T;
    29     scanf("%d",&T);
    30     for (int tt = 1; tt <= T ; tt++) {
    31         int n , w , k;
    32         scanf("%d %d %d",&n,&w,&k);
    33         for (int i = 0; i < n; i++) {
    34             int temp;
    35             scanf("%d %d", &temp ,point + i);
    36         }
    37         sort(point , point + n);
    38         int len = _decode(n);
    39         int MIN = point[0];
    40         memset(dp,0,sizeof(dp));
    41         for (int i = 1; i <= k; i++) {
    42             for (int j = 0; j < len; j++) {
    43                 int pre = lower_bound(decode,decode + len,decode[j] - w) - decode;
    44                 int l = lower_bound(point , point + n , decode[j] - w) - point;
    45                 int r = upper_bound(point , point + n , decode[j]) - point;
    46                 if(pre - 1 < 0) dp[i][j] = max(dp[i][j] , r - l);
    47                 else dp[i][j] = max(dp[i][j] , dp[i - 1][pre - 1] + (r - l));
    48                 //
    49                 dp[i][j] = max(dp[i][j] , dp[i][j - 1]);
    50                 // 关键部分
    51             }
    52         }
    53         int ans = 0;
    54         ans = dp[k][len - 1];
    55         cout << "Case " << tt << ": " << ans << endl;
    56     }
    57     return 0;
    58 }
  • 相关阅读:
    linux_进程管理
    Linux-日志管理
    Httpd
    Linux-源码安装包管理
    Linux-计划任务管理
    Linux-LVM管理
    Linux-系统磁盘管理
    Linux-yum工具的使用
    Linux-rpm包管理
    Linux-网络进阶管理
  • 原文地址:https://www.cnblogs.com/ticsmtc/p/5429150.html
Copyright © 2020-2023  润新知