洛谷 P1034 [NOIP2002 提高组] 矩形覆盖
记录问题和思考
该题使用的是DFS搜索,自定义了矩阵数据结构,通过矩阵离原点最近和最远的两个点确定了唯一矩阵。事实上矩阵的实现并不难。
DFS逻辑
类似装球问题,将每个点当做球,矩阵当做盒子,我们要做的其实就是遍历所有的装球可能情况,从而找出最好的那一种。(所以这不是搜索,而是遍历~ 好多答案都说的是暴搜 )
不过为了降低时间复杂度,需要进行一些简单的剪枝。
e.g. 当当前面积>最优值 return
问题与思考
主要遇到的问题在DFS函数的处理上,应该如何理解void dfs
的return
应该注意是否是递归
- 如果是,void是不能递归的,因为无返回值
- 如果不是,应该注意
void
的return
其实起到了剪枝的作用
虽然很多人都说是直接暴力搜索,但事实上如果没有用好这个
return
还是会超时滴~
最后这个覆盖问题真的很像聚类诶
代码
#include<iostream>
#include<math.h>
#include<cstdio>
#include<vector>
using namespace std;
/********
矩形覆盖
装球问题dfs
********/
int n, k, ans = 0x7f7f7f7f;
struct Rectangle
{
// X1 和 Y1 一定要初始化,因为是矩阵中最小的点
int X1 = 0x7f7f7f7f, X2, Y1 = 0x7f7f7f7f, Y2;
int cnt = 0;
int calcu_area() {
if (!cnt) {
return 0;
}
else {
return(X2 - X1) * (Y2 - Y1);
}
}
void add_node(int x, int y) {
X1 = min(X1, x);
Y1 = min(Y1, y);
X2 = max(X2, x);
Y2 = max(Y2, y);
cnt += 1;
}
bool inter_each(Rectangle t) {
if (Y1 > t.Y2 || t.Y1 > Y2 || X1 > t.X2 || t.X1 > X2) {
return 0;
}
return 1;
}
}Rects[5];
// 阶梯遍历所有组合
bool check() {
for (int i = 0; i < k - 1; ++i) {
for (int j = i + 1; j < k; ++j) {
if (Rects[i].inter_each(Rects[j])) {
return 0;
}
}
}
return 1;
}
// return 剪枝 只要return的不是dfs递归就不会G
void dfs(int num, int area, vector<vector<int> >& nodes){ // 全搜索
if (area >= ans) {
return;
}
if (num < n) {
for (int i = 0; i < k; ++i) {
Rectangle temp = Rects[i];
Rects[i].add_node(nodes[num][0], nodes[num][1]);
//cout << area << ' ';
//if (area == 4) {
// printf("X1 Y1 :(%d, %d) X2 Y2 :(%d, %d)\n", temp.X1, temp.Y1, temp.X2, temp.Y2);
//}
dfs(num + 1, area + Rects[i].calcu_area() - temp.calcu_area(), nodes);
Rects[i] = temp;
}
}
else if(check()){
ans = min(ans, area);
}
}
int main() {
cin >> n >> k;
vector<vector<int> > nodes(n + 1);
for (int i = 0; i < n; ++i) {
int x, y;
cin >>x >> y;
nodes[i].push_back(x);
nodes[i].push_back(y);
}
dfs(0, 0, nodes);
cout << ans;
return 0;
}