标签:思想 超时 cost 算法 小数 cin int() 三分法 pen
【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;
}
标签:思想 超时 cost 算法 小数 cin int() 三分法 pen
原文地址:https://www.cnblogs.com/qswx/p/9155679.html