ZOJ2928 Mathematical contest in modeling(爬山算法)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2928


参考学习的yamiedie_的博文:http://blog.csdn.net/u013654696/article/details/22336419

关于爬山算法和模拟退火的简介:http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html


Mathematical contest in modeling

Time Limit: 3 Seconds       Memory Limit: 32768 KB

This year's mathematical contest in modeling in ZJU will come soon. The students loving the contest have already made their teams. We consider a simple model: A team contains three students, one of them is good at maths, the second of them is good at computer, and the third one is good at writing. Now they want to estimate their team's relative power level in all participant teams. They use their grades in school instead of their real modeling abilities now because before the contest no other criterions more properly can be used. The grade of a student is a nonnegative real number no more than 1000. A team's modeling ability can be represented by three real numbers a, b, and c. a is the grade of the student which is good at maths, b is the grade of the one which is good at computer, and c is the grade of the one which is good at writing. If they know the average modeling ability of all teams, each team can compare their own team's modeling ability with the average modeling ability and then estimates their relative modeling power level in all teams.

Assume two teams' modeling abilities are a1, b1, c1 and a2, b2, c2 respectively, then the difference between their modeling abilities is defined as sqrt((a1-a2)^2+(b1-b2)^2+(c1-c2)^2). The average modeling ability of all teams is three real numbers which can be considered as a team's modeling ability, and the sum of the differences between this modeling ability and all teams' modeling abilities is minimum.

Your task is to calculate the average modeling ability of all teams.

Input

There are multiple test cases. Each teat case begins with a line containing a integer n, 3 <= n <= 100, which is the number of all teams. Then n lines follow, each line contains three real numbers ai, bi and ci, 0.00 <= ai, bi, ci <= 1000.00, which is a team's modeling ability.

Output

For each test case, print the average modeling ability of all teams in a line rounded to three decimal places after the decimal point. It is guaranteed that the answer is unique.

Sample Input

4
100.00 100.00 100.00
1000.00 100.00 100.00
100.00 1000.00 100.00
100.00 100.00 1000.00

Sample Output

250.000 250.000 250.000



题意:空间中有n个点,现在要求出一个点ans,使得这个点到所有n个点的距离之和最小。


一开始还以为是计算几何。。OTZ

题目中说明了这样的点只有1个,然后可以发现到距离之和是一个单峰函数,即只有一个最小值,即找出的最优解就是全局最优解
(证明什么的还是算了,总之不服你举个反例)
(如果还是不能相信是单峰函数,那么可以考虑模拟退火算法)
设定每次的步长逐渐减小,在三维能够到达的26个方向中,每次都找到能使距离之和更小的一个点,然后逐渐减少步长,这样可以保证最后逐渐趋于稳定,即为所求的最优解。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
#define eps 1e-8

struct point
{
       double x,y,z;
       point(){}
       point(double _x,double _y,double _z)
       {
                    x=_x;y=_y;z=_z;
       }
       point operator - (const point &b) const
       {
             return point(x-b.x,y-b.y,z-b.z);
       }
       double len()
       {
              return sqrt(x*x+y*y+z*z);
       }
}p[105],now;

int dir[30][3];
int n;

double dis(point a,point b)
{
       return (a-b).len();
}

void init() //生成三维的方向数组
{
    int x=0;
    for (int i=-1;i<=1;i++)
    {
        for (int j=-1;j<=1;j++)
        {
            for (int k=-1;k<=1;k++)
            {
                dir[x][0]=i;dir[x][1]=j;dir[x][2]=k;++x;
            }
        }
    }
    return;
}

double zh(point now)//求出距离之和
{
       double ans=0;
       for (int i=0;i<n;i++)
       {
           ans+=dis(now,p[i]);
       }
       return ans;
}

int main()
{
    init();//生成三维方向数组
    while (scanf("%d",&n)!=EOF)
    {
          for (int i=0;i<n;i++)
          {
              scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
          }
          now=point(0.0,0.0,0.0);
          double stp=-1,ans=zh(now);
          for (int i=0;i<n;i++)//找到初始步长,由于答案不可能在多面体外部,所以初始步长可以设为到点的距离最大值
          {
              double x=dis(now,p[i]);
              if (x>stp) stp=x;
          }
          while (stp>eps)//步长为0时停止循环,此时已经趋于稳定
          {
                point pre=now;
                double ans=zh(now);
                for (int i=0;i<27;i++)
                {
                    point unow=point(pre.x+dir[i][0]*stp,pre.y+dir[i][1]*stp,pre.z+dir[i][2]*stp);//向i方向前进一个步长
                    double tmp=zh(unow);
                    if (tmp<ans) {ans=tmp;now=unow;}//若当前点优于现在的最优解,则更新最优解(注意作为爬山起点的pre点暂时没有改变)
                }
                stp=stp*0.992;//减少步长,使步长趋于稳定(选取的数字要在不超时的可能下尽量大一点)
          }
          printf("%.3lf %.3lf %.3lf\n",now.x,now.y,now.z);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值