题四 矩形覆盖(存盘名NOIPG4)
[问题描述]:
在平面上有 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)
[输出]:
输出至屏幕。格式为:
一个整数,即满足条件的最小的矩形面积之和。
[输入输出样例]
d.in :
4 2
1 1
2 2
3 6
0 7
屏幕显示:
4
【思路】
回溯法。
搜索依次确定每个点属于哪一个矩形,时间复杂度为O(50^4)。最优解剪枝+如果相交则剪枝。
在网上看到了DP的做法:
f[i][j][k]=min{ f[i][l][k-1]+S(l+1,j) }
算法并不完美(只出现了矩形包含的点连续的情况,还有可能不连续),因为数据比较弱所以才能AC,但不失为一种可以借鉴的思路。
【dfs代码】
1 #include<iostream> 2 #include<cstring> 3 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 4 using namespace std; 5 6 const int maxn = 50+10; 7 struct Matrix{ 8 int a,b,c,d; 9 bool flag; 10 Matrix() { flag=false; } 11 }re[5]; 12 13 int x[maxn],y[maxn]; 14 int n,m,ans; 15 16 bool in(int x,int y,Matrix A) { 17 return (x>=A.a && x<=A.b && y>=A.c && y<=A.d); 18 } 19 20 bool can(int i,int j) { 21 bool ans=0; 22 if(in(re[i].a,re[i].c,re[j])) return 1; 23 if(in(re[i].a,re[i].d,re[j])) return 1; 24 if(in(re[i].b,re[i].c,re[j])) return 1; 25 if(in(re[i].b,re[i].d,re[j])) return 1; 26 return 0; 27 } 28 29 void dfs(int d) { 30 Matrix tmp; 31 int sum=0; 32 FOR(i,1,m) 33 if(re[i].flag) 34 { 35 sum += (re[i].b-re[i].a)*(re[i].d-re[i].c); 36 FOR(j,i+1,m) 37 if(re[j].flag && (can(i,j))) return ; 38 } 39 40 if(sum>=ans) return ; 41 if(d>n) { ans=sum; return ; } 42 FOR(i,1,m) { 43 tmp=re[i]; 44 if(!re[i].flag) { 45 re[i].flag=1; 46 re[i].a=re[i].b=x[d]; 47 re[i].c=re[i].d=y[d]; 48 } 49 else { 50 re[i].a=min(re[i].a,x[d]); 51 re[i].b=max(re[i].b,x[d]); 52 re[i].c=min(re[i].c,y[d]); 53 re[i].d=max(re[i].d,y[d]); 54 } 55 dfs(d+1); 56 re[i]=tmp; 57 } 58 } 59 60 int main() { 61 ios::sync_with_stdio(false); 62 cin>>n>>m; 63 FOR(i,1,n) cin>>x[i]>>y[i]; 64 ans=1e9; 65 dfs(1); 66 cout<<ans; 67 return 0; 68 }
【dp代码】
1 #include<iostream> 2 #define Max 1000000 3 using namespace std; 4 5 int n,m,ans=Max,x[52],y[52],f[52][52][5]={0}; 6 7 int High(int i,int j){ 8 int maxh=0,minh=1000,temp=i; 9 while(temp<=j) 10 maxh=max(maxh,y[temp++]); 11 temp=i; 12 while(temp<=j) 13 minh=min(minh,y[temp++]); 14 return maxh-minh; 15 } 16 17 18 void Dp(){ 19 for(int i=1;i<=n;++i) 20 for(int j=1;j<=n;++j) 21 for(int k=2;k<=m;++k) 22 f[i][j][k]=Max; 23 24 for(int i=1;i<=n;++i) 25 for(int j=i+1;j<=n;++j) 26 f[i][j][1]=(x[j]-x[i])*High(i,j); 27 for(int i=1;i<=n;++i) 28 for(int k=1;k<=m;++k) 29 f[i][i][k]=0; 30 31 for(int k=2;k<=m;++k) 32 for(int i=1;i<=n;++i) 33 for(int j=i+1;j<=n;++j) 34 for(int l=i+1;l<=j;++l) 35 f[i][j][k]=min(f[i][j][k],f[i][l-1][k-1]+(x[j]-x[l])*High(l,j)); 36 37 ans=min(ans,f[1][n][m]); 38 } 39 40 int main() 41 { 42 cin>>n>>m; 43 for(int i=1;i<=n;++i) 44 cin>>x[i]>>y[i]; 45 46 for(int i=1;i<=n;++i) 47 for(int j=i+1;j<=n;++j) 48 if(x[i]>x[j]) {swap(x[i],x[j]);swap(y[i],y[j]);} 49 else if(x[i]==x[j]&&y[i]>=y[j]) swap(y[i],y[j]); 50 51 Dp(); 52 53 for(int i=1;i<=n;++i) 54 swap(x[i],y[i]); 55 56 for(int i=1;i<=n;++i) 57 for(int j=i+1;j<=n;++j) 58 if(x[i]>x[j]) {swap(x[i],x[j]);swap(y[i],y[j]);} 59 else if(x[i]==x[j]&&y[i]>=y[j]) swap(y[i],y[j]); 60 61 Dp(); 62 63 cout<<ans<<endl; 64 return 0; 65 66 }