N个点的 费马点

平面中给定N个点的坐标(x, y), 找到离点(m, n)最近的一个点。  该点称为这N个点的 费马点。

该问题是POJ上面的一个题目

参考链接1

参考链接2

代码一

#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;

#define MAX_NUM 128
/*
 *http://www.programlife.net/poj-2420-polygon-fermat-point.html
 *http://hi.baidu.com/novosbirsk/item/c3631ee832189fd5ea34c910
 *http://poj.org/problem?id=2420
 */
typedef struct TagPoint
{
	double x;
	double y;
}Point;

inline double pt_distance(const Point &a, const Point &b)
{
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

double fermat_point(Point pt[], int n, Point &ptres)
{
	Point u, v;
	double step = 0.0, curlen, explen, minlen;
	int i, j, k, idx;
	bool flag = false;
	u.x = u.y = v.x = v.y = 0.0;
	for(int i =0; i < n; ++i)
	{
		step += fabs(pt[i].x) + fabs(pt[i].y);
		u.x += pt[i].x;
		u.y += pt[i].y;
	}
	u.x /= n;
	u.y /= n;
	while(step > 1e-5)
	{
		for(k = 0; k < 10; step /= 2, ++k)
			for(int i = -1; i <= 1; ++i)
				for(j = -1; j <= 1; ++j)
				{
					v.x = u.x + step*i;
					v.y = u.y + step*j;
					curlen = explen = 0.0;
					for(idx = 0; idx < n; ++idx)
					{
						curlen += pt_distance(u, pt[idx]);
						explen += pt_distance(v, pt[idx]);
					}
					if(curlen > explen)
					{
						u = v;
						minlen = explen;
						flag = 1;
					}
				}
	}
	ptres = u;
	return flag? minlen: curlen;
}

int main()
{
	int n, i;
	double res;
	Point pt[MAX_NUM], ptres;
	while(EOF != scanf("%d", &n))
	{
		for(int i = 0; i < n; ++i)
			scanf("%lf %lf", &pt[i].x, &pt[i].y);
		res = fermat_point(pt, n, ptres);
		if(res - (int)(res) > 0.5)
			printf("%d\n", (int)(res+1));
		else
			printf("%d\n", (int)res);
	}
	return 0;
}


代码二

#include <cstdio>
#include <cmath>
#define PRECISION 1e-8
#define N 101
struct POINT {
    double x, y;
    POINT(double x, double y) :
        x(x), y(y) {
    }
    POINT() :
        x(0), y(0) {
    }
};
POINT plist[N];
inline double sqr(double x) {
    return x * x;
}
double pt_distance(const POINT &p1, const POINT &p2) {
    return sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y));
}
double get_all_dis(const POINT &p, int n)
{
	double ans = 0.0;
	for(int i = 0; i < n; ++i)
		ans += pt_distance(plist[i], p);
	return ans;
}

int main()
{
	int i, n;
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
		scanf("%lf%lf", &plist[i].x, &plist[i].y);
	POINT st = plist[0];
	double step = 100, mind = get_all_dis(st, n);
	while(step > 0.2)
	{
		int ok = 1;
		while(ok)
		{
			POINT tmp, nt;
			double t;
			ok = 0, nt = st;
			
			tmp = POINT(st.x, st.y + step);
            t = get_all_dis(tmp, n);
            if (t < mind)
                mind = t, ok = 1, nt = tmp;

            tmp = POINT(st.x, st.y - step);
            t = get_all_dis(tmp, n);
            if (t < mind)
                mind = t, ok = 1, nt = tmp;

            tmp = POINT(st.x + step, st.y);
            t = get_all_dis(tmp, n);
            if (t < mind)
                mind = t, ok = 1, nt = tmp;

            tmp = POINT(st.x - step, st.y);
            t = get_all_dis(tmp, n);
            if (t < mind)
                mind = t, ok = 1, nt = tmp;

            st = nt;
		}
		step /= 2.0;
	}
	int ans = (int)(mind+0.5)*100/100;
	printf("%d\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值