[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 }
时间: 2024-12-20 16:51:43

[DP] Light Oj 1017 Brush(III)的相关文章

Light OJ 1248 - Dice (III) 概率DP

n个面的骰子 求每个面至少扔到一次的期望值 设dp[i]为已经扔了i个不同面的期望值 dp[n] = 0 求dp[0] 因为dp[i]为还需要扔i个不同的面 每次可能扔中已经扔过的面或者没有扔到过的面2中情况 所以dp[i] = (i/n)*dp[i] + (n-i)/n*dp[i+1] +1 等号2边都有dp[i] 移项得dp[i] = dp[i+1]+n/(n-i) #include <cstdio> #include <cstring> #define imax 100005

DP [light oj 1013] Love Calculator

1013 - Love Calculator Yes, you are developing a 'Love calculator'. The software would be quite complex such that nobody could crack the exact behavior of the software. So, given two names your software will generate the percentage of their 'love' ac

Light OJ 1018 - Brush (IV)

题目大意: 一个二维平面上有N个点,一把刷子,刷一次可以把一条线上的所有点都刷掉.问最少刷多少次,可以把全部的点都刷完 状态压缩DP, 用记忆化搜索来写, 需要有个优化不然会超时. ======================================================================================== #include<cstdio> #include<cstring> #include<iostream> #in

light oj 1248 - Dice (III)(期望)

Given a dice with n sides, you have to find the expected number of times you have to throw that dice to see all its faces at least once. Assume that the dice is fair, that means when you throw the dice, the probability of occurring any face is equal.

[水+期望dp] light oj 1030 Discovering Gold

题意: 给n个点,每个点都有一个财宝. 你从1这个点开始出发,假设你在i这个点,每次随机走1~min(6,n-i)步. 每到达一个点就拿走财宝. 问最后拿到财宝的期望. 思路: 水的题目. dp[n]=v[n] 然后逐个往前推. 就是注意一下步数是 1~min(6,n-i) 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #inc

Light OJ 1019 - Brush (V)(图论-dijkstra)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1019 题目大意:Tanvir想从节点1的位置走到节点n的位置, 输出最短距离, 如果不存在输出"Impossible". 解题思路:dijkstra模版题 代码如下: #include<bits/stdc++.h> using namespace std; typedef long long LL; const int INF = 0x3f3f3f3f;

light oj 1422 - Halloween Costumes (区间dp)

1422 - Halloween Costumes PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is planning to attend as many parties as he can. Since it's Ha

Light OJ 1406 Assassin`s Creed 状态压缩DP+强连通缩点+最小路径覆盖

题目来源:Light OJ 1406 Assassin`s Creed 题意:有向图 派出最少的人经过全部的城市 而且每一个人不能走别人走过的地方 思路:最少的的人能够走全然图 明显是最小路径覆盖问题 这里可能有环 所以要缩点 可是看例子又发现 一个强连通分量可能要拆分 n最大才15 所以就状态压缩 将全图分成一个个子状态 每一个子状态缩点 求最小路径覆盖 这样就攻克了一个强连通分量拆分的问题 最后状态压缩DP求解最优值 #include <cstdio> #include <cstri

Light OJ 1316 A Wedding Party 最短路+状态压缩DP

题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差不多 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两点之前的最短路 然后只考虑那些商店 个数小于15嘛 就是TSP问题 状态压缩DP搞一下 状态压缩姿势不对 有必要加强 #include <cstdio> #include <algorithm> #include <queue> #include <vector>