bzoj-3680 吊打XXX

141 篇文章 0 订阅
75 篇文章 0 订阅
题意:

给出平面上n个有质量的点;

求这n个点的质心位置;

n<=10000;


题解:

这个似乎没什么好的算法啊。。。

但是如果模拟一下这个过程,就会得到一个有点意思的算法——爬山算法;

爬山算法通常被用于计算几何最优化问题的骗分;

与模拟退火不同,它要求答案函数单峰,或者可以说模拟退火是对爬山算法的改进吧;

想象这个绳结被这些点拉着,那么无论初始在哪里,都会到那个质心位置;

那就从任意任意一个点出发,向这个点的合外力方向走一段;

走着走着就到答案点啦!

具体一点的话,每一步走多少呢?

可以暂且设为一个值T;

第一步走T这么长,第二步走短一些,第三步再短...直到步长小于EPS为止;

这样yy一下,似乎最后还是会到质心位置嘛;

注意这里其实是不严格的,显然最终的解受第一步长T和变短的数量有关;

但是如果参数设置合理,最终得到的解就会在误差允许范围内了;

这个算法我不会算复杂度,不过同样和参数有关就是了,精度要求很高时不要使用这种算法;

至于为什么不写模拟退火。。显然单峰问题爬山比较靠谱嘛!

(其实我只是模拟退火写挂了被卡调不出来)


代码:


#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 11000
using namespace std;
const double EPS=1e-10;
const double INF=1e100;
struct Point
{
	double x,y;
	Point(){}
	Point(double _,double __):x(_),y(__){}
	friend Point operator +(Point a,Point b)
	{
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator -(Point a,Point b)
	{
		return Point(a.x-b.x,a.y-b.y);
	}
	friend Point operator *(double a,Point b)
	{
		return Point(a*b.x,a*b.y);
	}
	friend double operator *(Point a,Point b)
	{
		return a.x*b.x+a.y*b.y;
	}
	friend double len(Point a)
	{
		return sqrt(a*a);
	}
}p[N];
double g[N];
int n;
double drand()
{
	return rand()%1000/1000.0;
}
Point calc(Point a)
{
	Point ret=Point(0,0);
	for(int i=1;i<=n;i++)
	{
		ret=ret+g[i]/len(p[i]-a)*(p[i]-a);
	}
	return 1/len(ret)*ret;
}
Point slove(Point ans,double T)
{
	Point next,dt;
	while(T>EPS)
	{
		dt=T*calc(ans);
		next=ans+dt;
		ans=next;
		T*=0.9;
	}
	return ans;
}
int main()
{
	int m,i,j,k;
	Point ans=Point(0,0);
	double ma=0;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%lf%lf%lf",&p[i].x,&p[i].y,g+i);
		ans.x+=p[i].x,ans.y+=p[i].y;
		ma=max(ma,max(fabs(p[i].x),fabs(p[i].y)));
	}
	ans.x/=n,ans.y/=n;
	ans=slove(ans,ma);
	printf("%.3lf %.3lf\n",ans.x,ans.y);
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值