Stars
Problem Description
There are N (1 ≤ N ≤ 400) stars in the sky. And each of them has a unique coordinate (x, y) (1 ≤ x, y ≤ N). Please calculate the minimum area of the rectangle (the edges of the rectangle must be parallel to the X, Y axes) that can cover at least K (1 ≤ K ≤ N) stars. The stars on the borders of the rectangle should not be counted, and the length of each rectangle’s edge should be an integer.
Input
Input may contain several test cases. The first line is a positive integer T (T ≤ 10), indicating the number of test cases below.
For each test cases, the first line contains two integers N, K, indicating the total number of the stars and the number of stars the rectangle should cover at least.
Each of the following N lines contains two integers x, y, indicating the coordinate of the stars.
Output
For each test case, output the answer on a single line.
Sample Input
2 1 1 1 1 2 2 1 1 1 2
Sample Output
1 2
Hint
Source
“浪潮杯”山东省第六届ACM大学生程序设计竞赛
题意:
在二维平面上有n个点,从中选出一个一个长方形,要求其中包括至少k个点,且面积最小。
题解:
由于平面中的点所在的位置在[n,n]之间。n最大为400。我们将平面看成一个01矩阵,并做一个前缀和。
枚举矩阵的上下界。然后枚举上界的左端点,二分寻找下界的右端点,使得子矩阵[(i,l) (j,r)] 满足其中的点的个数至少为k
需要注意的是,枚举子矩阵的方法和计算子矩阵中的点的个数
时间复杂度O(n^3*log(n))
#include<bits/stdc++.h>
using namespace std;
const int maxn = 450;
int maze[maxn][maxn];
int n,k;
bool check(int x,int y,int l,int r) {
int temp = maze[y][r] - maze[y][l-1] - maze[x-1][r] + maze[x-1][l-1];
return temp >= k;
}
int lowerbound(int x,int y,int sta) {
int l = sta,r = n;
while(l <= r)
{
int mid = (l+r)>>1;
if(check(x,y,sta,mid)) r = mid - 1;
else l = mid + 1;
}
if(l == n+1) return -1;
return l;
}
int main()
{
int caset;scanf("%d",&caset);
while(caset--)
{
memset(maze,0,sizeof(maze));
scanf("%d%d",&n,&k);
for(int i=0,u,v;i<n;i++) {
scanf("%d%d",&u,&v);
maze[u][v] = 1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) maze[i][j] += maze[i][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) maze[i][j] += maze[i-1][j];
int ans = n * n;
for(int i=1;i<=n;i++) {
for(int j=i;j<=n;j++) { /// 枚举矩阵的上下界
for(int l=1;l<=n;l++) { /// 枚举上界的左端点。
int r = lowerbound(i,j,l);
if(r != -1) {
ans = min(ans,(j-i+1)*(r-l+1));
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
思路二:
由于对于某些二分可以用尺取法进行优化,于是本题也可以使用尺取。
时间复杂度O(n^3)
/**
给出平面中 n 个整数点,求最小的至少可以覆盖 k 个点的矩形面积
把这个平面看作一个矩阵,有整数点的位置为 1 ,其他位置为 0 。
求出 (1,1) 到任意点 (n,m) 的矩阵和,然后枚举任意两行,
我们可以根据这两行中值的差求得当前判断的子矩阵的和,这里可以用尺取法,若满足条件,计算面积,取最小值。
将 平面问题转化为 矩阵中子矩阵问题
利用二维尺取法进行尺取。
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 500;
const int INF = 0x3f3f3f3f;
int maze[maxn][maxn];
int n,k;
int cal(int x,int y) {
int l = 1,r = 1;
int res = INF;
/// temp = 子矩阵[(x,l),(y,r)]中的点的个数
int temp = maze[y][r] - maze[y][l-1] - maze[x-1][r] + maze[x-1][l-1];
while(1) {
while(r < n && temp < k) {
r++;
temp = maze[y][r] - maze[y][l-1] - maze[x-1][r] + maze[x-1][l-1];
}
if(temp < k) break;
res = min(res,(y-x+1)*(r-l+1));
if(l < n) {
l++;
temp = maze[y][r] - maze[y][l-1] - maze[x-1][r] + maze[x-1][l-1];
}
else break;
}
return res;
}
int main()
{
int caset;scanf("%d",&caset);
while(caset--) {
memset(maze,0,sizeof(maze));
scanf("%d%d",&n,&k);
for(int i=0,u,v;i<n;i++) {
scanf("%d%d",&u,&v);
maze[u][v] = 1;
}
/// 预处理出 (1,1)到 (n,m) 的 子矩阵中的 点的个数
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
maze[i][j] += maze[i][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
maze[i][j] += maze[i-1][j];
int ans = n * n;
for(int i=1;i<=n;i++) { /// 枚举任意两行,其中包括单独的一行。枚举矩阵的上下界
for(int j=i;j<=n;j++) {
ans = min(ans,cal(i,j));
}
}
printf("%d\n",ans);
}
return 0;
}