Description
在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分别为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),如图1。
这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。当 k=2 时,可用如图2的两个矩形 sl,s2 覆盖,s1,s2 面积和为 4。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。
Input
有若干组测试数据。每组的第1行有两个整数n、k,分别表示平面点数和需用来覆盖这些点的矩形数。接下来有n行,每行有两个整数xi、yi,表示点的坐标(xi, yi),(0<=xi, yi<=500)。两组数据之间空一个空行。
Output
对每组测试数据,输出满足条件的最小的矩形面积之和。
Sample Input
4 21 12 23 60 7
Sample Output
4
思路:区间dp题,感觉还是蛮难的,dp[i][j][k]表示从第i个到第j个用了k个矩形覆盖所需要的最小面积,和能量项链有些相似。对k=1进行预处理,对k从2从小到大遍历每一个区间,再遍历区间内的每一个点。对每一个点来说,遍历每一种覆盖方法(例如k=4时,对某一个点有(1,3),(2,2),(3,1)几种覆盖方法)要么和左边的进行覆盖,要么和右边的进行覆盖,取两者中的最小值就是该点的最小覆盖面积。
思路:区间dp题,感觉还是蛮难的,dp[i][j][k]表示从第i个到第j个用了k个矩形覆盖所需要的最小面积,和能量项链有些相似。对k=1进行预处理,对k从2从小到大遍历每一个区间,再遍历区间内的每一个点。对每一个点来说,遍历每一种覆盖方法(例如k=4时,对某一个点有(1,3),(2,2),(3,1)几种覆盖方法)要么和左边的进行覆盖,要么和右边的进行覆盖,取两者中的最小值就是该点的最小覆盖面积。
#include<iostream>
#include<algorithm>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int dp[100][100][5];
//dp[i][j][k]: 覆盖i到j用k个矩形的最小面积
struct node{
int x,y;
friend bool operator < (node a,node b){
if(a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
}a[100];
int main(){
int n,m;
while(cin>>n>>m)
{
for(int i=0;i<n;i++){
cin>>a[i].y>>a[i].x;
}
sort(a,a+n) //对所有点按横坐标进行排序,便于dp;
memset(dp,0,sizeof(dp));
//for(int i=0;i<n;i++) cout<<a[i].x<<' '<<a[i].y<<endl;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
int Max=0,Min=INF;
for(int l=i;l<=j;l++){
Max=max(Max,a[l].y);
Min=min(Min,a[l].y);
}
dp[i][j][1]=abs(Max-Min)*(a[j].x-a[i].x); //用一个矩形覆盖任意两个点所需要的最小面积
}
}
// for(int i=0;i<n;i++){
// for(int j=0;j<n;j++){
// cout<<dp[i][j][1]<<' ';
// }
// cout<<endl;
// }
for(int i=n-1;i>=0;i--){ //从右开始遍历区间左端点
for(int j=i+1;j<n;j++){ //从小到大遍历区间右端点
for(int k=2;k<=m;k++){ //遍历矩形个数
for(int l=i+1;l<j;l++){ //遍历i+1~j-1的每一个覆盖断点
for(int t=1;t<k;t++){ //遍历每一种覆盖方法
if(!dp[i][j][k]) dp[i][j][k]=min(dp[i][l][t]+dp[l+1][j][k-t],dp[i][l][k-t]+dp[l+1][j][t]);
else dp[i][j][k]=min(dp[i][j][k],min(dp[i][l][t]+dp[l+1][j][k-t],dp[i][l][k-t]+dp[l+1][j][t]));
// cout<<i<<' '<<j<<' '<<k<<' '<<dp[i][j][k]<<endl;
}
}
}
}
}
cout<<dp[0][n-1][m]<<endl;
}
return 0;
}