狄多公主圈地的故事

来源:互联网 发布:淘宝商业模式研究 编辑:程序博客网 时间:2024/04/29 21:23

(二)狄多公主圈地的故事

题目描述

在希腊传说中,推罗国王穆顿有个聪明漂亮的公主叫狄多。狄多在她的王国里过着幸福
快乐的生活,自由自在、无忧无虑,可是好景不长,不幸的事情发生了,她的丈夫被她
的兄弟塞浦路斯王杀死了。

狄多赶紧逃亡到了非洲西海岸,她想在这儿生活下来,于是她拿出随身携带的珠宝、玉
器、金币,打算从当地酋长雅尔巴斯那里买些土地盖房子。狄多对酋长说:“我只要用一
张牛皮包起来的地方。”酋长想也没想,一块牛皮包起的地方能有多大啊,自己捡了个大
便宜,于是爽快的答应下来。狄多要了一头牛,把它杀了,剥下皮来,把牛皮剪成长长
的细条,准备用牛皮来圈地。她以海为界,用牛皮条圈了一个半圆,圈出了一块相当大的
面积。后来,狄多在那儿建立了迦太基城。今天,还保存着迦太基的古迹。

现在,请大家帮狄多公主一个忙。^_^。

为了建设城市,她需要从当地一片森林中的拥有者那里买一些木材,交易条件是这样
的,在有限面积的森林内,散布着一些树木,而不同的树可得到的木材体积也不相同。
狄多需要划出一个圆形区域,区域内的树木皆归她所有,当然,树木分布位置并不规
则。请大家帮助狄多,在树木总数与分布情况,每棵树的可得到的木材体积已知的情况
下,算一下最大可圈出的木材体积是多少。

可以将树木看做平面内的N个点,以点的权值M0,M1,...Mn表示每棵树可出产的木材体
积。圆的半径为R(注:在圆边上的点不算圈入圆内),求以圆圈地,最大可以圈到多大的
权值?

 

输入数据格式

第一行为点数N和半径R,N与R皆为整数。以空格分割,以回车结尾。

第二行开始到第N+1行,使用笛卡尔直角坐标系描述点的位置,并给出权限。顺序为横坐
标x,纵坐标y,权值M,以空格分割,以回车结尾。

其中,为了简化,N、R、x、y、M皆为正整数,即点在平面的第一象限内。

 

输出数据格式

一个数字,代表可以圈到的最大权值。 

样例

输入:

2 3

1 1 3

2 1 2 

输出:

5

 

原来在博客贴了一个做法,是错误的,原因是,目标圆的中心点未必与树木点重合

 

又搞了两个方法,估计还有问题,但也算是进了一步

1. 如果目标圆的中心点只是考虑整形类型,那么枚举所有的点,半径为R,求有最大权值的点,枚举的点是所有的整形点,不仅是树木点

2. 枚举 所有的2棵树为直径的所有的圆 和 所有的3棵树唯一确定的圆,找出其中半径严
格小于给定半径,而且包含木头的权值最大的那个圆

 

#define DOUBLEV(x) (x)*(x)
const int DEFAULT_FLOAT_ERROER = 0.0001;

struct FPOINT
{
 FPOINT(float X, float Y,int Weight):
 x(X),y(Y),weight(Weight)
 {};

float x;
float y;
int weight;
};

//
typedef vector<FPOINT> point_list_t;

// 计算距离
float CalDistance(FPOINT& a ,FPOINT &b)
{
 return sqrt(((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}

// 计算距离平方
float CalDistance2(FPOINT& a ,FPOINT &b)
{
 return (((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}

// 计算分子
float CalNumerator(FPOINT& point1,FPOINT& point2)
{
 // (a1^2-b1^2+a2^2-b2^2)
 float numerator =(DOUBLEV(point1.x)-DOUBLEV(point2.x)+DOUBLEV(point1.y)-DOUBLEV(point2.y));

 return numerator;
}

// 计算分母
float CalDenominator1(FPOINT& point1,FPOINT& point2 ,FPOINT& point3)
{
 // (a1-b1)(a2-c2) - (a1-c1)(a2-b2)
 float denominator = (point1.x-point2.x)*(point1.y-point3.y) - (point1.x-point3.x)*(point1.y-point2.y);

 return denominator;
}

// X坐标
float CalHorizontal(FPOINT& point1,FPOINT& point2 ,FPOINT& point3)
{
 // (a1-b1)x1+(a2-b2)x2 = 1/2 (a1^2-b1^2+a2^2-b2^2);
 // (a1-c1)x1+(a2-c2)x2 = 1/2 (a1^2-c1^2+a2^2-c2^2);
 // =>
 // (a1-b1)(a2-c2)x1 + (a2-b2)(a2-c2)x2 = 1/2 (a1^2-b1^2+a2^2-b2^2)(a2-c2)
 // (a1-c1)(a2-b2)x1 + (a2-b2)(a2-c2)x2 = 1/2 (a1^2-c1^2+a2^2-c2^2)(a2-b2)

 float denominator = CalDenominator1(point1,point2,point3);

 if(denominator == 0)
  return -1;

 float numerator1 = CalNumerator(point1,point2)*(point1.y - point3.y);
 float numerator2 = CalNumerator(point1,point3)*(point1.y - point2.y);

 return 0.5*(numerator1 - numerator2) / denominator;
}

// 计算分母
float CalDenominator2(FPOINT& point1,FPOINT& point2 ,FPOINT& point3)
{
 // (a1-c1)(a2-b2)-(a1-b1)(a2-c2)
 float denominator = (point1.x-point3.x)*(point1.y-point2.y) - (point1.x-point2.x)*(point1.y-point3.y);

 return denominator;
}

// Y坐标
float CalVertical(FPOINT& point1,FPOINT& point2 ,FPOINT& point3)
{
 // (a1-b1)x1+(a2-b2)x2 = 1/2 (a1^2-b1^2+a2^2-b2^2);
 // (a1-c1)x1+(a2-c2)x2 = 1/2 (a1^2-c1^2+a2^2-c2^2);
 // =>
 // (a1-c1)(a1-b1)x1+(a1-c1)(a2-b2)x2 = 1/2 (a1-c1)(a1^2-b1^2+a2^2-b2^2);
 // (a1-c1)(a1-b1)x1+(a1-b1)(a2-c2)x2 = 1/2 (a1-b1)(a1^2-c1^2+a2^2-c2^2);

 float numerator1 = CalNumerator(point1,point2)*(point1.x - point3.x);
 float numerator2 = CalNumerator(point1,point3)*(point1.x - point2.x);

 float denominator = CalDenominator2(point1,point2,point3);

 if(denominator == 0)
  return -1 ;
 else
  return 0.5*(numerator1 - numerator2) / denominator;
}

// 是否在同一直线
bool Judge_Line(FPOINT& point1,FPOINT& point2 ,FPOINT& point3)
{
 // (b1-a1)(c2-a2) = (b2-a2)(c1-a1)
 float k1 = (point2.x-point1.x)*(point3.y-point1.y);
 float k2 = (point2.y-point1.y)*(point3.x-point1.x);

 if(point1.x == point2.x)
 {
  if((point1.x - point3.x) < DEFAULT_FLOAT_ERROER)
   return true;
  else
   return false;
 }else
 {
  float k = (point1.y-point2.y)/(point1.x-point2.x);
  float b = point1.y - k * point1.x ;
  float y = k * point3.x + b ;

  if((y-point3.y) < DEFAULT_FLOAT_ERROER)
   return true ;
  else
   return false;
 }
}

//
void use_way2()
{
 point_list_t point_list ;

 point_list.push_back(FPOINT(1, 1 ,3));
 point_list.push_back(FPOINT(2, 1 ,2));

 point_list.push_back(FPOINT(10, 12 ,13));
 point_list.push_back(FPOINT(12, 10 ,13));

 int nRadius  = 3 ;
 int nMaxWeight = 0 ;

 float nTargetX = 0 ;
 float nTargetY = 0 ;

 // 实数点坐标

 // 1. 两点为直径的圆
 // n*n*n

 for(size_t potIndex1 = 0 ;potIndex1 < point_list.size() ; potIndex1 ++)
 {
  for (size_t potIndex2  = 0; potIndex2 < point_list.size() ; potIndex2 ++)
  {
   // 直径
   float diameter = CalDistance2(point_list[potIndex1],point_list[potIndex2]);

   if((diameter - 4*nRadius*nRadius) < DEFAULT_FLOAT_ERROER) // 等于
   {
    float centerX = (point_list[potIndex1].x + point_list[potIndex2].x) / 2;
    float centerY = (point_list[potIndex1].y + point_list[potIndex2].y) / 2;

    int nTmpWeight = 0 ;

    FPOINT point(centerX,centerY,1); //中心点

    for (size_t potIndex  = 0; potIndex < point_list.size() ; potIndex ++)
    {
     //
     float nDistance = CalDistance2(point,point_list[potIndex]);

     if(nDistance < nRadius*nRadius) // 确实是要小于
      nTmpWeight+= point_list[potIndex].weight;
    }

    if(nTmpWeight > nMaxWeight)
    {
     nTargetX = centerX;
     nTargetY = centerY;
     nMaxWeight = nTmpWeight ;
    }
   }
  }
 }

 // 2. 三点确定一个外接圆 n*n*n*n
 for(size_t potIndex1 = 0 ;potIndex1 < point_list.size() ; potIndex1 ++)
  for (size_t potIndex2  = 0; potIndex2 < point_list.size() ; potIndex2 ++)
   for (size_t potIndex3  = 0; potIndex3 < point_list.size() ; potIndex3 ++)
   {
    FPOINT& point1 =  point_list[potIndex1];
    FPOINT& point2 =  point_list[potIndex2];
    FPOINT& point3 =  point_list[potIndex3];

    bool line = Judge_Line(point1,point2 ,point3);

    if(line)
     continue ;
    else
    {
     float centerX = CalHorizontal( point1, point2 , point3);
     float centerY = CalVertical( point1, point2 , point3);
     
     int nTmpWeight = 0 ;

     FPOINT point(centerX,centerY,1); //中心点

     for (size_t potIndex  = 0; potIndex < point_list.size() ; potIndex ++)
     {
      //
      float nDistance = CalDistance2(point,point_list[potIndex]);

      if(nDistance < nRadius*nRadius) // 确实是要小于
       nTmpWeight+= point_list[potIndex].weight;
     }

     if(nTmpWeight > nMaxWeight)
     {
      nTargetX = centerX;
      nTargetY = centerY;
      nMaxWeight = nTmpWeight ;
     }
    }
   }

}

void use_way1()
{
 point_list_t point_list ;

 point_list.push_back(FPOINT(1, 1 ,3));
 point_list.push_back(FPOINT(2, 1 ,2));

 point_list.push_back(FPOINT(10, 12 ,13));
 point_list.push_back(FPOINT(12, 10 ,13));
 point_list.push_back(FPOINT(13, 13 ,11));

 int nRadius  = 3 ;
 int nMaxWeight = 0 ;

 int nMaxX = 0 ;
 int nMaxY = 0 ;
 int nMinX = 1000000;
 int nMinY = 1000000;

 //////////////////////////////////////////////////////////////////////////

 for (size_t potIndex = 0 ;potIndex < point_list.size() ; potIndex ++)
 {
  FPOINT& point = point_list[potIndex];

  if(point.x > nMaxX)
   nMaxX = point.x ;
  if(point.x < nMinX)
   nMinX = point.x ;
  if(point.y > nMaxY)
   nMaxY = point.y ;
  if(point.y < nMinY)
   nMinY = point.y ;
 }

 int nTargetX = 0 ;
 int nTargetY = 0 ;

 // 穷举所有点(不止树木为坐标的点),整数类型

 for (int horizontalIndex = nMinX ; horizontalIndex <= nMaxX ; horizontalIndex ++ )
  for (int verticalIndex = nMinY ; verticalIndex <= nMaxY ; verticalIndex ++)
  {
   int nTmpWeight = 0 ;

   FPOINT point(horizontalIndex,verticalIndex,1);

   for (size_t nearIndex  = 0; nearIndex < point_list.size() ; nearIndex ++)
   {
    int nDistance = CalDistance(point,point_list[nearIndex]);

    if(nDistance < nRadius)
     nTmpWeight+= point_list[nearIndex].weight;
   }

   if(nTmpWeight > nMaxWeight)
   {
    nTargetX = horizontalIndex;
    nTargetY = verticalIndex ;
    nMaxWeight = nTmpWeight ;
   }
  }

  printf("%d %d %d/n",nTargetX , nTargetY , nMaxWeight);
}

 

 

原创粉丝点击