题目大意:有N个污点,每个污点有相应的坐标。现在有一个宽度为w的刷子,刷子可以使用k次,刷的时候,可以横刷到无穷
问最多可以刷掉多少个污点
解题思路:先离散化,预处理出每个y坐标的点,并统计一下该同一y坐标下,有多少个点
再处理一下,如果刷子的最下面刚好是该y坐标时,能刷到的所有污点数
接着就是DP了,用dp[i][j]表示刷子使用了i次,第i次刷的时候,刷子的最底部刷的是第j个y坐标的最大污点数
则dp[i][j] = dp[i - 1][k] + num[j], 其中y[k] + w < y[j],num[j]表示刷子的最下面刷的是y[j]时,能刷到的污点数
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
struct Point{
int x, y;
}P[N];
int n, w, k, cnt, cas = 1;
int num[N], y[N], dp[N][N];
int cmp(const Point &a, const Point &b) {
return a.y < b.y;
}
void init() {
scanf("%d%d%d", &n, &w, &k);
for (int i = 1; i <= n; i++)
scanf("%d%d", &P[i].x, &P[i].y);
sort(P + 1, P + 1 + n, cmp);
cnt = 1;
y[1] = P[1].y;
num[1] = 1;
for (int i = 2; i <= n; i++) {
if (P[i].y == P[i - 1].y) num[cnt]++;
else {
y[++cnt] = P[i].y;
num[cnt] = 1;
}
}
for (int i = 1; i <= cnt; i++)
for (int j = i + 1; j <= cnt; j++)
if (y[i] + w >= y[j]) num[i] += num[j];
}
void solve() {
int ans = 0;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= cnt; i++) {
dp[1][i] = num[i];
ans = max(ans, dp[1][i]);
}
for (int i = 2; i <= k; i++)
for (int j = 1; j <= cnt; j++)
for (int l = 1; l < j; l++) {
if (y[l] + w >= y[j]) break;
if (y[l] + w < y[j] && dp[i][j] < dp[i - 1][l] + num[j]) {
dp[i][j] = dp[i - 1][l] + num[j];
ans = max(ans, dp[i][j]);
}
}
printf("Case %d: %d\n", cas++, ans);
}
int main() {
int test;
scanf("%d", &test);
while (test--) {
init();
solve();
}
return 0;
}