洛谷 P1034 [NOIP2002 提高组] 矩形覆盖

洛谷 P1034 [NOIP2002 提高组] 矩形覆盖

题目链接

记录问题和思考


该题使用的是DFS搜索,自定义了矩阵数据结构,通过矩阵离原点最近和最远的两个点确定了唯一矩阵。事实上矩阵的实现并不难。

DFS逻辑

类似装球问题,将每个点当做球,矩阵当做盒子,我们要做的其实就是遍历所有的装球可能情况,从而找出最好的那一种。(所以这不是搜索,而是遍历~ 好多答案都说的是暴搜 )
不过为了降低时间复杂度,需要进行一些简单的剪枝。
e.g. 当当前面积>最优值 return

问题与思考

主要遇到的问题在DFS函数的处理上,应该如何理解void dfsreturn
应该注意是否是递归

  • 如果是,void是不能递归的,因为无返回值
  • 如果不是,应该注意voidreturn其实起到了剪枝的作用

虽然很多人都说是直接暴力搜索,但事实上如果没有用好这个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;
}
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值