题目描述
题目描述
在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),见图一。
这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。当 k=2 时,可用如图二的两个矩形 sl,s2 覆盖,s1,s2 面积和为 4。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。
输入输出格式
输入格式:
n k xl y1 x2 y2 ... ...
xn yn (0<=xi,yi<=500)
输出格式:
输出至屏幕。格式为:
一个整数,即满足条件的最小的矩形面积之和。
输入输出样例
输入样例#1: 复制
4 2
1 1
2 2
3 6
0 7
输出样例#1: 复制
4
最最保险的做法:dfs+剪枝,当k>=4时也能做。
原则:枚举每一个点,可以任意加入到k个矩形中的某一个,从而得到最优解。
原理:易证明对于每一种i(i<k)个矩形的情形,其结果一定不是最优的(可将其中某个矩形再次划分)
每个矩形只需记录其4至点,即可求面积。
#include<cstdio>
#include<iostream>
using namespace std;
struct dot
{
int x,y;
} a[51];
struct mtrx
{
int l,r,u,d;
bool flag;
} p[5];
int n,m,ans=0x7f7f7f7f;
bool in(mtrx a, int x, int y)
{
if (x>=a.l&&x<=a.r&&y>=a.d&&y<=a.u) return 1;
return 0;
}
bool judge(mtrx a, mtrx b)
{
if (in(a,b.l,b.u)) return 1;
if (in(a,b.l,b.d)) return 1;
if (in(a,b.r,b.u)) return 1;
if (in(a,b.r,b.d)) return 1;
return 0;
}
void dfs(int num)
{
int value=0;
for (int i=1; i<=m; i++)
{
if (p[i].flag)
{
for (int j=i+1; j<=m; j++)
if (p[i].flag&&judge(p[i],p[j])) return;
}
value+=(p[i].r-p[i].l)*(p[i].u-p[i].d);
}
if (value>=ans) return;
if (num>n){
ans=value;
return;
}
for (int i=1; i<=m; i++)
{
mtrx tmp=p[i]; //tmp的初值
if (p[i].flag==0)
{
p[i].flag=1;
p[i].l=p[i].r=a[num].x;
p[i].u=p[i].d=a[num].y;
dfs(num+1); p[i]=tmp; //回溯 (一定要回溯彻底,用tmp变量)
break;
}
else
{
p[i].r=max(p[i].r,a[num].x); p[i].l=min(p[i].l,a[num].x);
p[i].u=max(p[i].u,a[num].y); p[i].d=min(p[i].d,a[num].y);
dfs(num+1);
p[i]=tmp; //回溯 (一定要回溯彻底,用tmp变量)
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++)
scanf("%d%d",&a[i].x,&a[i].y);
dfs(1);
printf("%d",ans);
return 0;
}