码迷,mamicode.com
首页 > 其他好文 > 详细

NOIP2002 矩形覆盖

时间:2015-10-07 21:33:56      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:

题四 矩形覆盖(存盘名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     }

 

NOIP2002 矩形覆盖

标签:

原文地址:http://www.cnblogs.com/lidaxin/p/4859544.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!