[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 }

 

posted @ 2016-04-25 02:49  ACMZZ  阅读(327)  评论(1编辑  收藏  举报