【Electric Fences】电力篱笆

【Problem description】

农夫约翰已经决定建造电网。他已经把他的农田围成一些奇怪的形状,现在必须找出安放电源的最佳位置。
  对于段电网都必须从电源拉出一条电线。电线可以穿过其他电网或者跨过其他电线。电线能够以任意角度铺设,从电源连接到一段电网的任意一点上(也就是,这段电网的端点上或者在其之间的任意一点上)。这里所说的“一段电网”指的是呈一条线段状的电网,并不是连在一起的几段电网。若几段电网连在一起,那么也要分别给这些电网提供电力。
  已知所有的 F(1 <= F <= 150)段电网的位置(电网总是和坐标轴平行,并且端点的坐标总是整数,0 <= X,Y <= 100)。你的程序要计算连接电源和每段电网所需的电线的最小总长度,还有电源的最佳坐标。

电源的最佳坐标可能在农夫约翰的农田中的任何一个位置,并不一是整数。

【Input format】

第一行包括 F ——电网的数量。
下面的 F 行每行包括两个 X,Y 对,表示这段电网的两个端点。

【Output format】

只有一行,输出三个浮点数,相邻两个之间留一个空格。假定你的电脑的输出库会正确地对小数进行四舍五入。
  这三个数是: 电源最佳坐标的 X 值,
  电源最佳坐标的 Y 值,和
  需要的电线的总长度(要最小)。

【Algorithm design】

Greed Enumeration

【Problem analysis】

离散程度为0.1 如果强行枚举

对于地图上1000*1000个点穷举

算出其到150条篱笆的距离

到单条篱笆的距离用数学思想 是O(1)的算法

复杂度为O(10^6*150)

后来想是不是可以使用三分法取一条线上的最值

但是不满足单调函数性质

所以此法作废

发现对于一个区域内的点相差必然不会太大

推论出答案点必然位于较优的整数点附近

可以把所有整数点花费计算出来

Sort之后

取一定数量的点进行寻找答案

因为对于单个点算距离是O(150)

一个整数点可以引申出400个点

所以取了1000个点可以恰好不超时

O(1000*400*150)

将着1000个点引申出的所有小数点进行排序即可

还有一点要注意 在列举点的时候有的点位于同一个矩形内

所以可以加个vit 避免冗余的计算

【Source code】

#include <bits/stdc++.h>

#define F(i,j,k) for(int i=j;i<=k;i++)

#define D(i,j,k) for(int i=j;i>=k;i--)

#define max_cnt 151

#define bound_map 101

using namespace std;

double dx[4]={1,-1,1,-1};

double dy[4]={1,-1,-1,1};

int cnt_fence,cnt_int,vit[bound_map][bound_map];

double x_least,y_least,cost_least,x_ans,y_ans,bound_fence[max_cnt][2][2],dis_int[bound_map][bound_map],point_map[2];

//bound_fence「顺序」「始/末」「横/纵」

struct stud

{

   double cost;

   double x;

   double y;

}cost_int[bound_map*bound_map];

bool cmp(stud p,stud q)

{

   if(p.cost!=q.cost)return p.cost<q.cost;

   if(p.x!=q.x)return p.x<q.x;

   return p.y<q.y;

}

double mi(double x)

{

   return x*x;

}

double distance(double sub[])

{

   double dis=0;

   F(turn,1,cnt_fence)

      F(direct,0,1)

      if(bound_fence[turn][0][direct]==bound_fence[turn][1][direct])

      {

         if(sub[1-direct]>=bound_fence[turn][0][1-direct]&&sub[1-direct]<=bound_fence[turn][1][1-direct])

            dis+=abs(bound_fence[turn][0][direct]-sub[direct]);

         else

            dis+=sqrt(mi(bound_fence[turn][0][direct]-sub[direct])+min(mi(sub[1-direct]-bound_fence[turn][0][1-direct]),mi(sub[1-direct]-bound_fence[turn][1][1-direct])));

         break;

      }

   return dis;

}

void search(int direct)

{

   for(double sub1=0;sub1<=1;sub1+=0.1)

   for(double sub2=0;sub2<=1;sub2+=0.1)

   {

      point_map[0]=x_least+dx[direct]*sub1;

      point_map[1]=y_least+dy[direct]*sub2;

      double dis_now=distance(point_map);

      if(dis_now<cost_least)

      {

         cost_least=dis_now;

         x_ans=point_map[0];

         y_ans=point_map[1];

      }

   }

   return;

}

void input()

{

   cin>>cnt_fence;

   F(i,1,cnt_fence)

   {

      F(j,0,1)F(k,0,1)cin>>bound_fence[i][j][k];

      F(k,0,1)

      if(bound_fence[i][0][k]>bound_fence[i][1][k])

         swap(bound_fence[i][0][k],bound_fence[i][1][k]);

   }

   return;

}

void work_int()

{

   for(point_map[0]=0;point_map[0]<bound_map;point_map[0]++)

      for(point_map[1]=0;point_map[1]<bound_map;point_map[1]++)

         dis_int[(int)point_map[0]][(int)point_map[1]]=distance(point_map);

   F(i,0,bound_map-1)

      F(j,0,bound_map-1)

      {

         cnt_int++;

         cost_int[cnt_int].cost=dis_int[i][j];

         cost_int[cnt_int].x=(double)i;

         cost_int[cnt_int].y=(double)j;

      }

   sort(cost_int+1,cost_int+cnt_int+1,cmp);

   return;

}

void work_dou()

{

   cost_least=cost_int[1].cost;

   x_ans=cost_int[1].x;

   y_ans=cost_int[1].y;

   F(turn,1,min(1000,cnt_int))

   {

      x_least=cost_int[turn].x;

      y_least=cost_int[turn].y;

      vit[(int)x_least][(int)y_least]=1;

      F(i,0,3)

      {

         if(x_least+dx[i]<bound_map&&x_least+dx[i]>=0&&y_least+dy[i]<bound_map&&y_least+dy[i]>=0&&!vit[(int)(x_least+dx[i])][(int)(y_least+dy[i])])

            search(i);

      }

   }

   return;

}

void output()

{

   printf("%.1lf %.1lf %.1lf\n",x_ans,y_ans,cost_least);

   return;

}

int main()

{

   freopen("fence.in","r",stdin);

   freopen("fence.out","w",stdout);

   input();

   work_int();

   work_dou();

   output();

   return 0;

}

猜你喜欢

转载自www.cnblogs.com/qswx/p/9155679.html