• NOIP2002 矩形覆盖


    题四 矩形覆盖(存盘名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     }
  • 相关阅读:
    HDOJ 1093
    HDOJ 1089
    HDOJ 1094
    qsort函数
    HDOJ 1092
    HDOJ 1091
    NYOJ 448(贪心)
    HDOJ 1090
    HDOJ 1097(幂取模)
    winform用户输入查询与拼音首字母的结合,提高用户的操作体验
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4859544.html
Copyright © 2020-2023  润新知