求n个点的费马点的花式乱搞

  今天下午做了微软2014编程之美初赛第一场,被虐成翔了,排名才1025。仅仅过掉了第一题的大小数据,以及第三题的小数据。其中第三题觉得挺好玩的,于是就额外乱搞了一下。

题目3 : 活动中心

时间限制: 12000ms
单点时限: 6000ms
内存限制: 256MB

描述

A市是一个高度规划的城市,但是科技高端发达的地方,居民们也不能忘记运动和锻炼,因此城市规划局在设计A市的时候也要考虑为居民们建造一个活动中心,方便居住在A市的居民们能随时开展运动,锻炼强健的身心。

城市规划局希望活动中心的位置满足以下条件:

1. 到所有居住地的总距离最小。

2. 为了方便活动中心的资源补给和其他器材的维护,活动中心必须建设在A市的主干道上。


为了简化问题,我们将A市摆在二维平面上,城市的主干道看作直角坐标系平的X轴,城市中所有的居住地都可以看成二维平面上的一个点。

现在,A市的城市规划局希望知道活动中心建在哪儿最好。


输入

第一行包括一个数T,表示数据的组数。

接下来包含T组数据,每组数据的第一行包括一个整数N,表示A市共有N处居住地

接下来N行表示每处居住地的坐标。


输出

对于每组数据,输出一行“Case X: Y”,其中X表示每组数据的编号(从1开始),Y表示活动中心的最优建造位置。我们建议你的输出保留Y到小数点后6位或以上,任何与标准答案的绝对误差或者相对误差在10-6以内的结果都将被视为正确。


数据范围

小数据:1 ≤ T ≤ 1000, 1 ≤ N ≤ 10

大数据:1 ≤ T ≤ 10, 1 ≤ N ≤ 105

对于所有数据,坐标值都是整数且绝对值都不超过106



样例解释

样例1:活动中心的最优建造位置为(1.678787, 0)



样例输入
1
3
1 1
2 2
3 3
样例输出
Case 1: 1.678787

  这道题是POJ2420的弱化版,POJ2420是求二维平面上n个点的费马点,也就是与这n个点距离总和最小的点。而这道题加了一个要求是这个点必须在X轴上,求其横坐标。

  一开始我很SB地写二分,TLE了几发还以为是精度控制太严格了,后来一想这题的解空间显然不是单调的,怎么可以二分……想了想感觉解空间是单峰的否则不可搞,于是写了发三分,过掉了小数据,大数据无悬念地TLE了。

#include
#include
#include
using namespace std;
const int MAXN=100005;
const double eps=1e-7;
const int INF=0x3f3f3f3f;
struct Point {
    double x,y2;
} p[MAXN];
int t,n;
double Trichotomy() {
    double l=INF,r=-INF;
    for(int i=0; ieps) {
        double m1=(2*l+r)/3,m2=(l+2*r)/3,distm1=0,distm2=0;
        for(int i=0; i

  后来渣诚提到了牛顿迭代法(虽然他可耻地CE了),SRF提到了梯度下降(虽然也没过大数据),其实是一码事。于是也打算写一发。牛顿迭代是平方收敛的,所以速度上肯定比三分要快得多。写的中途求导错了一次debug了半天,目前是能过样例,但hihoCoder这平台十分蛋疼,比赛结束后不能提交,所以暂时无法验证对不对(过小数据估计还是没问题的)。

#include
#include
const int MAXN=100005;
const double eps=1e-7;
struct Point {
    double x,y2;
} p[MAXN];
int t,n;
double dist[MAXN];
double Newton() {
    double x=0;
    for(int i=0; i

  然后去看了看POJ2420的Discuss,发现不少神犇们令人发指地写了模拟退火……NExPlain也在Damocles的群里提到他一度想写粒子群算法,由于一定很慢放弃了……我感觉这帮家伙们实在太神不能直视,但哥好歹也是玩过神经网络粒子群算法人工免疫算法的人好吧,怎么可以被神犇们虐成这样?

  于是查了查资料,也鼓捣出一个模拟退火来。同样只验证过样例。我估计大数据只有这货有可能过了。

#include
#include
#include
#include
const int MAXN=100005;
const double eps=1e-7;
const int RANGE=1000000;
struct Point {
    double x,y2;
} p[MAXN];
int t,n;
double SA(int cnt=3) {
    double ret,dmin=1e40,rate=0.83;
    srand(time(NULL));
    while(cnt--) {
        double step=rate*RANGE,x=(rand()%RANGE+1.0)/RANGE,dist=0;
        for(int i=0; ieps; step*=rate)
            for(int i=-1; i<=1; i+=2) {
                double pt=x+step*i,tmp=0;
                for(int j=0; j

  此外,CLX提到一点是出题方没有注意到的,我认为是微软出题人的疏漏;就是在某些情况下,费马点是存在多解情况的……

  比方说如下数据:

  1
  2
  1 0
  2 0

  这时候在(1,0)和(2,0)之间的所有点都是满足条件的。除非出题人写了Special Judge,或者干脆没有这种数据(那也应该在题干里说明一下不是么……);这种数据下,三分和模拟退火都全身而退,而牛顿迭代会死循环,因为这种数据下作为分母的二阶导恒为0(也许SRF的TLE是因为这个),需要加一个特判。

  于是这道题就结束了吧……为了拿衣服明天还得继续打,so sad……

  后记:首先表示自己拿到了衣服好开心~其次表示现在衣服还没有邮寄到我手里……最后表示我又看了一些人的blog,发现三分写得好是可以过掉大数据的,果然是一开始写挫了么= =于是我又优化了一下常数更新了上面的代码,至于现在能不能过大数据,兴许再也没办法知道了……

你可能感兴趣的:(有趣的小笔记)