Distant Galaxy   poj 3141

题意:  给出二维坐标上的n 个点 , 找出一个矩形 , 使得矩形边界上的点尽可能多次 。

可以看出这是一个枚举的题目 , 但如果把矩形的每条边度枚举 , 那么肯定会超时 , 所有 , A这个题目的关键在于怎么来枚举 , 枚举那些东西?

通过观察 , 我们可以发现 , 除非所有点都在一行或一列上 , 否则 , 最优矩形的4条边都至少有一个点(一个角上的点同时算两条边的) 。  但有不能枚举所有的边 , 因此我们考虑部分枚举 。

所以我们只枚举矩形的上下边界 , 上下边界最多只有 100*50 中可能 。

对于左右边界 , 我们也是通过枚举 , 这样之所以不同于全部枚举 , 在于 , 通过上下边界的枚举我们去除了很多没必要的枚举 。 我们定义3个数组: on[i](当这条线是左边界时边界上的点) , on2[i](当这条线是右边界时边界上的点 , 和 on 的区别是:on2 包含竖线和上下边界共有的点 , on 不包含) ,  ,xy[i] (上下边界位于这条线左边的点数的数量) , 可以推出:
      xy[j] - xy[i] + on2[j] + on[i]  这就是当前这个矩形边界上的点。

代码:

#include
#include
#include
using namespace std;

struct point
{
      int x ,y;
      bool operator < (const point &rhs) const
      {
            return x < rhs.x;
      }
};

const int maxn = 100 + 10;
struct point p[maxn];
int n , m , y[maxn] , on[maxn] , on2[maxn] ;
int xy[maxn];

int max(int x , int y)
{
      if(x > y)  return x;
      return y;
}

int solve()
{
      sort(p , p+n);
      sort(y , y+n);
      m = unique(y , y+n) - y;  //地址运算
      if(m <= 2)  return n;
      int ans = 0 , i , j;
      for(int a = 0; a < m; a++)
            for(int b = a+1; b < m; b++)
            {
                  int ymin = y[a] , ymax = y[b];

                  int k = 0;
                  for( i = 0; i < n; i++)
                  {
                        if(i == 0 || p[i].x != p[i-1].x)
                        {
                              k++;
                              on[k] = on2[k] = 0;
                              xy[k] = 0;
                              for(int f = 0; f < n; f++)
                                    if(p[f].y == ymin || p[f].y == ymax)
                                    {
                                          if(p[f].x < p[i].x)  xy[k] += 1;
                                    }
                        }
                        //if(p[i].y < ymin && p[i].y < ymax)    on[k]++;
                        if(p[i].y >= ymin && p[i].y <= ymax)
                        {
                              if(p[i].y > ymin && p[i].y < ymax)  on[k]++ , on2[k]++;
                              else on2[k]++;
                        }
                  }
                  if(k <= 2)  return n;
                 
                  int m = 0;
                  for( j = 1; j <= k; j++)
                        for(i = 1; i <= k; i++)
                        {
                              if(j == i)  continue ;
                              int gy = on2[i] + on[j] + xy[i]-xy[j];
                              ans = max(ans , gy);
                        }
            }
            return ans;
}

int main()
{
      int kase = 0;
      while(cin>>n && n)
      {
            for(int i = 0; i < n; i++)
            {
                  cin>>p[i].x>>p[i].y;
                  y[i] = p[i].y;
            }
            printf("Case %d: %d\n" , ++kase , solve());
      }
      return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值