P1034 矩形覆盖

题目描述

在平面上有nnn个点(n≤50n \le 50n≤50),每个点用一对整数坐标表示。例如:当 n=4n=4n=4 时,444个点的坐标分另为:p1p_1p1​(1,11,11,1),p2p_2p2​(2,22,22,2),p3p_3p3​(3,63,63,6),P4P_4P4​(0,70,70,7),见图一。

这些点可以用kkk个矩形(1≤k≤41 \le k \le 41≤k≤4)全部覆盖,矩形的边平行于坐标轴。当 k=2k=2k=2 时,可用如图二的两个矩形 s1,s2s_1,s_2s1​,s2​ 覆盖,s1,s2s_1,s_2s1​,s2​ 面积和为4 44。问题是当nnn个点坐标和kkk给出后,怎样才能使得覆盖所有点的kkk个矩形的面积之和为最小呢?
约定:覆盖一个点的矩形面积为000;覆盖平行于坐标轴直线上点的矩形面积也为000。各个矩形必须完全分开(边线与顶点也都不能重合)。

输入输出格式

输入格式:

 

nkn knk
x1y1x_1 y_1x1​y1​
x2y2x_2 y_2x2​y2​
... ...

xnynx_n y_nxn​yn​ (0≤xi,yi≤5000 \le x_i,y_i \le 5000≤xi​,yi​≤500)

 

输出格式:

 

输出至屏幕。格式为:

111个整数,即满足条件的最小的矩形面积之和。

 

输入输出样例

输入样例#1: 复制

4 2
1 1
2 2
3 6
0 7

输出样例#1: 复制

4

 以下参考别人代码:

#include<iostream>
using namespace std;
int n,m,ans=250000+2;
int num;
struct Node{
	int x,y;
};
Node pt[51];
struct Rcl{
	int rx,uy;
	int lx,ly;
};
Rcl rc[7]; 
bool isIn(int i,int j){
	if(pt[i].x<rc[j].lx||pt[i].x>rc[j].rx) return false;
	if(pt[i].y<rc[j].ly||pt[i].y>rc[j].uy) return false;
	return true; 
}

bool judge(int i){
	for(int j=1;j<=num;j++){
		if(i==j){
			continue;
		}else{
			if(rc[i].rx>=rc[j].lx&&rc[i].rx<=rc[j].rx&&rc[i].ly>=rc[i].ly&&rc[i].ly<=rc[j].uy) return false;
			if(rc[i].rx>=rc[j].lx&&rc[i].rx<=rc[j].rx&&rc[i].uy>=rc[j].ly&&rc[i].uy<=rc[j].uy) return false;
			if(rc[i].lx>=rc[j].lx&&rc[i].lx<=rc[j].rx&&rc[i].ly>=rc[i].ly&&rc[i].ly<=rc[j].uy) return false;
			if(rc[i].lx>=rc[j].lx&&rc[i].lx<=rc[j].rx&&rc[i].uy>=rc[j].ly&&rc[i].uy<=rc[j].uy) return false;                    
			
		}
	}
	return true;
}
int s(int i){
	return (rc[i].rx-rc[i].lx)*(rc[i].uy-rc[i].ly);
}
int sum(){
	int _sum=0;
	for(int i=1;i<=num;i++){
		_sum+=s(i);
	}
	return _sum;
}
void dfs(int i){
	if(i>n){
		ans=min(ans,sum());
		return;
	}	
	if(sum()>=ans){
		return; 
	}
	for(int j=1;j<=num;j++){
		if(isIn(i,j)){
			dfs(i+1);
		}else{
			int prelx=rc[j].lx;
			int prerx=rc[j].rx;
			int preuy=rc[j].uy;
			int prely=rc[j].ly;
			rc[j].lx=min(pt[i].x,rc[j].lx);
			rc[j].rx=max(pt[i].x,rc[j].rx);
			rc[j].ly=min(pt[i].y,rc[j].ly);
			rc[j].uy=max(pt[i].y,rc[j].uy);
			if(!judge(j)){
				rc[j].lx=prelx;
				rc[j].rx=prerx;
				rc[j].uy=preuy;
				rc[j].ly=prely;
				continue;
			}
			dfs(i+1);
			rc[j].lx=prelx;
			rc[j].rx=prerx;
			rc[j].uy=preuy;
			rc[j].ly=prely;
		}
	}
	if(num<m){
		num++;
		rc[num].lx=pt[i].x;
		rc[num].rx=pt[i].x;
		rc[num].uy=pt[i].y;
		rc[num].ly=pt[i].y;
		dfs(i+1);
		num--;
	}
	return;
}


int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>pt[i].x>>pt[i].y;
	}
	dfs(1);
	cout<<ans<<endl;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值