Lightoj - 1017 - Brush (III) 详解(经典线性DP)

来源:互联网 发布:只有粤语的电影软件 编辑:程序博客网 时间:2024/05/21 20:17

1017 - Brush (III)
   PDF (English)StatisticsForum
Time Limit: 2 second(s)Memory Limit: 32 MB

Samir returned home from the contest and got angry after seeing his room dusty. Who likes to see a dusty room after a brain storming programming contest? After checking a bit he found a brush in his room which has width w. Dusts are defined as 2D points. And since they are scattered everywhere, Samir is a bit confused what to do. He asked Samee and found his idea. So, he attached a rope with the brush such that it can be moved horizontally (in X axis) with the help of the rope but in straight line. He places it anywhere and moves it. For example, the y co-ordinate of the bottom part of the brush is 2 and its width is 3, so the y coordinate of the upper side of the brush will be 5. And if the brush is moved, all dusts whose y co-ordinates are between 2 and 5 (inclusive) will be cleaned. After cleaning all the dusts in that part, Samir places the brush in another place and uses the same procedure. He defined a move as placing the brush in a place and cleaning all the dusts in the horizontal zone of the brush.

You can assume that the rope is sufficiently large. Since Samir is too lazy, he doesn't want to clean all the room. Instead of doing it he thought that he would use at most k moves. Now he wants to find the maximum number of dust units he can clean using at most k moves. Please help him.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a blank line. The next line contains three integers N (1 ≤ N ≤ 100), w (1 ≤ w ≤ 10000) and k (1 ≤ k ≤ 100)N means that there are N dust points. Each of the next N lines contains two integers: xi yi denoting the coordinates of the dusts. You can assume that (-109 ≤ xi, yi ≤ 109) and all points are distinct.

Output

For each case print the case number and the maximum number of dusts Samir can clean using at most k moves.

Sample Input

Output for Sample Input

2

 

3 2 1

0 0

20 2

30 2

 

3 1 1

0 0

20 2

30 2

Case 1: 3

Case 2: 2


题意:坐标系里有n个点,一个宽度为w的刷子可以擦去这些点(边缘擦到也算),刷子可以横向无限移动,问移动k次最多可以擦去多少点。

思路:显然与点的横坐标无关,将纵坐标排序,预处理:以刷子的底边擦去一个点i会向上影响多少个点cnt[i]。

状态转移方程:dp[i][j]=max(dp[i-1][j],dp[i-mv[i]][j-1]+mv[i]),前一项表示不删点i,后一项表示把它和它会影响的点都删掉。


注意这里的dp【i】【j】表示的是  第i个点,第j次移动所能粉刷的最多的点,是粉刷的最多的点,所以dp[i][j]=max(dp[i-1][j],dp[i-mv[i]][j-1]+mv[i]),如果i点不粉刷,他是从dp[i-1][j]转移过来的,因为i-1代表i并没有被粉刷。


一开始我想到了第i个点,第j次移动,也想到了以i点为底,w为区间的移动。。可是在状态标记上卡住了。。。其实这个跟背包差不过啊。。。为什么想不到呢。。既然i点能影响cnt【i】个点,也就是要刷i点,上面cnt个点都被刷了,所以应该从没有这cnt个点的状态转移过来,不就是i-cnt【i】吗。。。代表前面的最多的点,从那个状态+上cnt【i】。。。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 105;int dp[maxn][maxn], y[maxn], cnt[maxn];int cmp(int a, int b){    return a > b;}int main(){    int t, ca = 1, n, k, w, tx;    cin >> t;    while(t--)    {        memset(dp, 0, sizeof(dp));        cin >> n >> w >> k;        for(int i = 0; i < n; i++)            cin >> tx >> y[i];        sort(y, y+n, cmp);        for(int i = 0; i < n; i++)        {            int temp = 0;            for(int j = i; j >= 0; j--)            {                if(y[j]-y[i] <= w)                    temp++;            }            cnt[i] = temp;        }        for(int j = 1; j <= k; j++)            for(int i = 0; i < n; i++)        {            if(i >= cnt[i])                dp[i][j] = max(dp[i-1][j], dp[i-cnt[i]][j-1] + cnt[i]);            else                dp[i][j] = cnt[i];        }        printf("Case %d: %d\n", ca++, dp[n-1][k]);    }    return 0;}



1 0
原创粉丝点击