描述
在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7)。
这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。当 k=2 时,可用如图二的两个矩形 s1,s2 覆盖,s1,s2 面积和为 4。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。
格式
输入格式
格式为
n k
xl y1
x2 y2
... ...
xn yn (0<=xi,yi<=500)
输出格式
一个整数,即满足条件的最小的矩形面积之和。
样例1
样例输入1
4 2
1 1
2 2
3 6
0 7
1 1
2 2
3 6
0 7
样例输出1
4题解
看着数据范围就是搜索了,这道题我用了三个剪枝(如果能算剪枝的话)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ans=1<<30;
struct dian {int x,y;} a[52];
struct jux{int xz,xy,ys,yx,tag;} b[5];
void init()
{
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
}
bool jiao(jux i,int x,int y)
{
if(x>=i.xz&&x<=i.xy&&y<=i.ys&&y>=i.yx) return true;
else return false;
}
bool check(jux i,jux j)
{
if(jiao(j,i.xz,i.yx)) return true;
if(jiao(j,i.xy,i.yx)) return true;
if(jiao(j,i.xz,i.ys)) return true;
if(jiao(j,i.xy,i.ys)) return true;
return false;
}
void dfs(int x)
{
int i,j,s=0;
for(i=1;i<=m;i++)//1、判断矩形是否重合
{if(b[i].tag)
{s+=(b[i].xy-b[i].xz)*(b[i].ys-b[i].yx);
for(j=i+1;j<=m;j++)//节省时间
{if(b[j].tag&&check(b[i],b[j])) return;}
}
}
if(s>=ans) return; //2、一种常用剪枝
if(x>n) {ans=s; return;}
jux t;
for(i=1;i<=m;i++)
{t=b[i];
if(!b[i].tag)
{b[i].xz=a[x].x; b[i].xy=a[x].x; b[i].ys=a[x].y; b[i].yx=a[x].y;
b[i].tag=1;
}
else
{b[i].xz=min(a[x].x,b[i].xz); b[i].xy=max(b[i].xy,a[x].x);
b[i].ys=max(b[i].ys,a[x].y); b[i].yx=min(b[i].yx,a[x].y);
}
dfs(x+1);
b[i]=t;
if(!t.tag) return;//3、保证每个矩形都用上
}
}
int main()
{
init(); dfs(1);
printf("%d\n",ans);
return 0;
}