HDU 1173 采矿(思路)

Problem Description
某天gameboy玩魔兽RPG。有一个任务是在一个富含金矿的圆形小岛上建一个基地,以最快的速度采集完这个小岛上的所有金矿。这个小岛上有n(0
这个小岛在一个二维直角坐标系中描述。

你的任务就是帮gameboy找一个建造基地的位置,使矿工能以最快的速度采完所有矿。
 

Input
输入数据有多组。每组数据的第一行是一个正整数n(0
 

Output
每一组输入数据对应一行输出,输出两个实数x,y(保留小数点后两位),也就是你找到的建造基地的位置坐标。如果坐标不唯一,可以任选一个输出。
 

Sample Input

41.0 1.03.0 1.03.0 3.01.0 3.00
 

Sample Output

2.00 2.00

题意:

给出n个笛卡尔坐标系上的点,找到一点(可以不在n个点中)在x,y轴上投影,到其他所有点在x,y轴上投影,距离和最短


思路:

先将其转化为2个,求1维最短距离和的子问题。

刚开始以为是平均数,后来发现平均数并不是最优解,如1,5,6。


下面是一维上答案是中位数的证明(伪

设金矿有n个,每个金矿在ai 点( ai < a(i+1) )

n == 1 时,答案在a1点

n == 2 时,答案在区间[a1,a2]上

n  >  2 时, 答案在 [a1,an],[a2,an-1]……上,所以答案是中间的点,或线段上。


--------------------------------------------------------------------------------------------------------------


另一种写法 和 伪证明

证明前提是已知点上必定存在答案,这个不会证明,凭直觉。

dp求每点到所有点距离和

//a为坐标点,dpa为a到其余点距离和
for(int i = 1; i < n; i++)
{
    dpa[i] = dpa[i-1] + (a[i] - a[i-1])*i - (a[i] - a[i-1])*(n-i);
}

不难发现dpa是一个先减后增的数列,i>(n-i)时增,i<(n-i)时减。

这应该也可以说明答案是中位数吧。。。

--------------------------------------------------------------------------------------------------------------

代码:

直接求解:

#include
#include
using namespace std;

double a[1000005], b[1000005];

int main()
{
    int n;
    while(scanf("%d",&n), n)
    {
        for(int i = 0; i < n; i++) scanf("%lf%lf",&a[i],&b[i]);
        sort(a,a+n);
        sort(b,b+n);
        printf("%.2lf %.2lf\n",a[(n-1)/2], b[(n-1)/2]);
    }
    return 0;
}

dp:

#include
#include
using namespace std;

double a[1000005], b[1000005], dpa[1000005], dpb[1000005];

int main()
{
    int n;
//    freopen("F:\\my.txt","w",stdout);
    while(scanf("%d",&n), n)
    {
        for(int i = 0; i < n; i++) scanf("%lf%lf",&a[i],&b[i]);

        sort(a,a+n);
        sort(b,b+n);

        for(int i = 1; i < n; i++)
        {
            dpa[0] = a[i] - a[0];
            dpb[0] = b[i] - b[0];
        }


        for(int i = 1; i < n; i++)
        {
            dpa[i] = dpa[i-1] + (a[i] - a[i-1])*i - (a[i] - a[i-1])*(n-i);

            dpb[i] = dpb[i-1] + (b[i] - b[i-1])*i - (b[i] - b[i-1])*(n-i);
        }

        int ans1 = 0, ans2 = 0;

        for(int i = 1; i < n; i++)
        {
            if(dpa[i] < dpa[ans1]) ans1 = i;
            if(dpb[i] < dpb[ans2]) ans2 = i;
        }
        printf("%.2lf %.2lf\n",a[ans1], b[ans2]);
    }
    return 0;
}

你可能感兴趣的:(#,思路,线性DP)