题目描述
在平面上有 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
搜索。这题剪枝方法似乎多种多样。
这份代码的做法:
将读入的坐标按x和y从小到大排序,然后搜索将连续的i个点分在一起,期间判断问题是否可行,以及进行各种小优化。
1 /*By SilverN*/ 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 using namespace std; 8 int read(){ 9 int x=0,f=1;char ch=getchar(); 10 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 struct point{ 15 int x,y; 16 }a[60]; 17 int cmp(point a,point b){ 18 if(a.x==b.x)return a.y<b.y; 19 return a.x<b.x; 20 } 21 struct block{ 22 int x1,y1,x2,y2; 23 }b[5]; 24 int n,k; 25 int ans=1e9; 26 void DFS(int pos,int cnt,int smm){ 27 if(pos>n){ 28 ans=min(ans,smm); 29 return; 30 } 31 if(cnt>k)return; 32 int i,j; 33 b[cnt].x1=a[pos].x; 34 b[cnt].x2=a[pos].x; 35 b[cnt].y1=a[pos].y; 36 b[cnt].y2=a[pos].y; 37 for(i=pos;i<=n;i++){ 38 b[cnt].y2=max(b[cnt].y2,a[i].y); 39 b[cnt].x2=max(b[cnt].x2,a[i].x); 40 b[cnt].x1=min(b[cnt].x1,a[i].x); 41 b[cnt].y1=min(b[cnt].y1,a[i].y); 42 for(j=1;j<cnt;j++){ 43 if(b[cnt].x1<=b[j].x2 && b[cnt].y1<=b[j].y2)return; 44 } 45 if(i<n && cnt==k)continue; 46 DFS(i+1,cnt+1,smm+(b[cnt].x2-b[cnt].x1)*(b[cnt].y2-b[cnt].y1)); 47 } 48 return; 49 } 50 int main(){ 51 n=read();k=read(); 52 int i,j; 53 for(i=1;i<=n;i++){ 54 a[i].y=read();a[i].x=read(); 55 } 56 sort(a+1,a+n+1,cmp); 57 memset(b,-1,sizeof b); 58 DFS(1,1,0); 59 printf("%d\n",ans); 60 return 0; 61 }