poj 2420

题目概述

给定一个N边形所有顶点坐标x,y,求其费马点到所有顶点距离和
费马点是指到多边形所有顶点距离和最小的点

时限

1000ms/3000ms

输入

第一行正整数N,其后N行,每行两个整数x,y,输入到EOF为止

限制

1<=N<=100;0<=x,y<=10000

输出

每行一个数,为所求距离和,精确到整数

样例输入

4
0 0
0 10000
10000 10000
10000 0

样例输出

28284

讨论

计算几何?沾点边,主要思想是模拟退火?或者叫随机化变步长贪心?额感觉还是叫瞎猜比较合适,从给定的多边形顶点中随便找一个点开始,沿着上下左右四个方向移动相同距离,并分别计算到所有顶点距离和,取最小的一个(而且要比上一次小),记录移动后点的位置为新的起点,然后减小移动距离,再向四个方向移动,直到移动距离小于精度就可以返回距离和了
说是模拟退火,但其实只有几个for循环,实际的模拟退火比这个复杂的多,说是随机化变步长贪心,额只看见贪心了,没看见rand(),所以基本上只能叫瞎猜了
其实这个题用牛顿迭代法一样可解,不过需要一点高数的基础,而且写起来会比较麻烦,于是就没考虑
看讨论版说数据弱的出奇,看出来了,瞎猜都能猜对

题解状态

156K,0MS,C++,846B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 102
#define memset0(a) memset(a,0,sizeof(a))

int N;//顶点总数
int x[MAXN], y[MAXN];//存放顶点坐标
const int dx[4] = { -1,0,1,0 }, dy[4] = { 0,-1,0,1 };//点移动方向向量
double fun()
{
    for (int p = 0; p < N; p++)
        scanf("%d%d", &x[p], &y[p]);//input
    double x0 = x[0], y0 = y[0], least = INF;//取得第一个点 初始化最短距离和
    for (double p = 10000; p > 0.4; p /= 2)//由于坐标范围是0到10000 而且没有斜向移动 所以步长从10000开始 终点0.4是为了避免舍入误差 每次除以2有点太快 应该慢一些才是
        for (int i = 0; i < 4; i++) {
            double dis = 0, x1 = x0 + dx[i] * p, y1 = y0 + dy[i] * p;//初始化距离和 并算出移动后的点坐标
            for (int u = 0; u < N; u++)
                dis += sqrt((x1 - x[u])*(x1 - x[u]) + (y1 - y[u])*(y1 - y[u]));
            if (dis < least) {//当发现移动后更近时就要更新 这就是贪心
                least = dis;
                x0 = x1, y0 = y1;
            }
        }
    return least;
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    while (~scanf("%d", &N))//input
        printf("%.0lf\n", fun());//output
}

EOF

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值