标签:
题四 矩形覆盖(存盘名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
【思路】
Dfs。
首先将输入点按照xy递增的顺序排序。
搜索依次确定每个点属于哪一个矩形。最优解剪枝+如果相交则剪枝。
在网上看到了DP的做法:
f[i][j][k]=min{ f[i][l][k-1]+S(l+1,j) }
算法并不完美(只出现了矩形包含的点连续的情况,还有可能不连续),因为数据比较弱所以才能AC,但不失为一种可以借鉴的思路。
【dfs代码】
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 using namespace std; 5 6 struct data1 7 { 8 int x, y; 9 }p[51]; 10 struct data2 11 { 12 int l, r, u, d; 13 bool flag; 14 }re[5]; 15 int n, m, ans = 0x7fffffff; 16 bool in( data2 a, int xx, int yy ) 17 { 18 if( xx>=a.l && xx<=a.r && yy>=a.d && yy<=a.u ) 19 return 1; 20 else 21 return 0; 22 } 23 bool coin( data2 a, data2 b ) //判断是否相交 24 { 25 if( in( b, a.l, a.d ) ) return 1; 26 if( in( b, a.l, a.u ) ) return 1; 27 if( in( b, a.r, a.d ) ) return 1; 28 if( in( b, a.r, a.u ) ) return 1; 29 return 0; 30 } 31 void dfs( int k ) //一次确定每个点属于哪一个矩形 32 { 33 int i, j, s= 0; 34 data2 tmp; 35 36 for( i=1; i<=m; i++ ) 37 if( re[i].flag ) 38 { 39 s += ( re[i].r-re[i].l ) * ( re[i].u-re[i].d); 40 for( j=i+1; j<=m; j++ ) 41 if( re[j].flag && coin( re[i], re[j] ) ) //防止有两个矩形相交 //相交则dfs失败 42 return; 43 } 44 if( s>=ans ) return; //最优解剪枝 45 46 if( k>n ){ ans = s; return; } 47 for( i=1; i<=m; i++ ) //第k个点属于第i个矩形 48 { 49 tmp = re[i]; // 50 //更新re[i]的四至 51 if( !re[i].flag ) 52 { 53 re[i].l = p[k].x; re[i].r = p[k].x; 54 re[i].u = p[k].y; re[i].d = p[k].y; 55 re[i].flag = 1; 56 } 57 else 58 { 59 re[i].l = min( re[i].l, p[k].x ); 60 re[i].r = max( re[i].r, p[k].x ); 61 re[i].d = min( re[i].d, p[k].y ); 62 re[i].u = max( re[i].u, p[k].y ); 63 } 64 dfs( k+1 ); 65 re[i] = tmp; //回溯 66 } 67 } 68 int main() 69 { 70 int i; 71 scanf( "%d%d", &n, &m ); 72 for( i=1; i<=n; i++ ) 73 scanf( "%d%d", &p[i].x, &p[i].y ); 74 dfs( 1 ); 75 printf( "%d\n", ans ); 76 return 0; 77 }
【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 }
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/4859544.html