【Codeforces Beta Round 2C】【计算几何 转化 模拟退火】Commentator problem 求一个点,使得该点到三个圆的视角范围尽可能接近

C. Commentator problem
time limit per test
1 second
memory limit per test
64 megabytes
input
standard input
output
standard output

The Olympic Games in Bercouver are in full swing now. Here everyone has their own objectives: sportsmen compete for medals, and sport commentators compete for more convenient positions to give a running commentary. Today the main sport events take place at three round stadiums, and the commentator's objective is to choose the best point of observation, that is to say the point from where all the three stadiums can be observed. As all the sport competitions are of the same importance, the stadiums should be observed at the same angle. If the number of points meeting the conditions is more than one, the point with the maximum angle of observation is prefered.

Would you, please, help the famous Berland commentator G. Berniev to find the best point of observation. It should be noted, that the stadiums do not hide each other, the commentator can easily see one stadium through the other.

Input

The input data consists of three lines, each of them describes the position of one stadium. The lines have the format x,  y,  r, where (x, y) are the coordinates of the stadium's center ( -  103 ≤ x,  y ≤ 103), and r (1 ≤ r  ≤ 103) is its radius. All the numbers in the input data are integer, stadiums do not have common points, and their centers are not on the same line.

Output

Print the coordinates of the required point with five digits after the decimal point. If there is no answer meeting the conditions, the program shouldn't print anything. The output data should be left blank.

Sample test(s)
input
0 0 10
60 0 10
30 30 10
output
30.00000 0.00000


#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
const int N=0,M=0,Z=1e9+7,ms63=1061109567;
struct Circle
{
	double x,y,r;
}c[3];
double ang[3];
const int dy[4]={-1,0,0,1};
const int dx[4]={0,-1,1,0};
double K(double x)
{
	return x*x;
}
double Dis(double x,double y,double xx,double yy)
{
	return sqrt(K(x-xx)+K(y-yy));
}
double Val(double x,double y)
{
	for(int i=0;i<3;++i)ang[i]=Dis(x,y,c[i].x,c[i].y)/c[i].r;
	double val=0;
	for(int i=0;i<3;++i)val+=K(ang[i]-ang[(i+1)%3]);
	return val;
}
int main()
{
	double x=0,y=0;
	for(int i=0;i<3;++i)
	{
		scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
		x+=c[i].x/3;y+=c[i].y/3;
	}
	double err=Val(x,y);
	double step=1;
	for(int tim=1;tim<=1e5;++tim)
	{
		bool flag=0;
		double X,Y;
		for(int i=0;i<4;++i)
		{
			double xx=x+dx[i]*step,yy=y+dy[i]*step;
			double val=Val(xx,yy);
			if(val<err)
			{
				err=val;
				flag=1;
				X=xx;Y=yy;
			}
		}
		if(flag){x=X;y=Y;}
		else step/=2;
	}
	if(err<1e-6)printf("%.5f %.5f\n",x,y);
	return 0;
}
/*
【trick&&吐槽】
啦啦啦!

【题意】
给你三个圆,让你找到一个点,使得从这个点出发,看三个圆的视角范围的角度都一样。
如果有多个满足要求的点,我们希望找到一个点,使得这个视角范围的角度尽可能大。
(如果无解就不输出)

【类型】
计算几何公式求解or模拟退火

【分析】
这题可以直接解方程,用计算几何的方法做。
然而最好的,最值得学习有推广价值的算法还是——模拟退火。

什么是模拟退火呢?以后我们可以再慢慢具体学习。(才不是因为我现在不会啦~  T_T )
按照这道题的学习,大体上是这样做——
bas,设计估价函数
1,初始找一个近似最优解,
2,然后在最优解的四周寻求更优解。这里要保证步长不要太小,否则可能陷入局部最优解。
3,重复步骤2,适当调整步长,继续寻找最优解,直到达到精度要求。

在这道题上——
估价函数要先求出(距离/半径),这个数值和视角大小有相应的一一对应关系。
	然后求出三个圆pair的(距离/半径)的差值的平方和,作为估价函数。
	这个值越小,越接近零,显然对于三个圆的视角越接近。
1是重心
2初始为1,找得到更优就继续走。找不到更优就步长缩半
3直到一定的次数或一定的精度
然后这道题就做完啦!做完啦!做完啦!
以后再来加深学习模拟退火哦~~!

====================================================================
当然这题有解方程做法啦。因为满足要求的点数其实一筛就没几个了哦~以后再补!

【时间复杂度&&优化】
O(模拟退火次数)

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值