您的位置:首页 > 其它

HDU 1173 采矿(思路)

2018-03-28 09:46 274 查看
[align=left]Problem Description[/align]某天gameboy玩魔兽RPG。有一个任务是在一个富含金矿的圆形小岛上建一个基地,以最快的速度采集完这个小岛上的所有金矿。这个小岛上有n(0<n<1000000)个金矿,每个金矿的矿藏量是相等的。而且这个小岛的地势非常平坦,所以基地可以建在小岛的任何位置,每个金矿的采矿速度只跟矿藏到基地的路程长度有关。为了不让这个任务太无聊,游戏设计者对这个小岛施了个“魔法”,规定矿工在小岛上只能正南正北正西正东走。也就是说矿工不能斜着在岛上走。

这个小岛在一个二维直角坐标系中描述。

你的任务就是帮gameboy找一个建造基地的位置,使矿工能以最快的速度采完所有矿。
 
[align=left]Input[/align]输入数据有多组。每组数据的第一行是一个正整数n(0<n<1000000),表示小岛上有n个金矿。在接下来的n行中,每行有两个实数x,y,表示其中一个金矿的坐标。n=0表示输入数据结束。
 
[align=left]Output[/align]每一组输入数据对应一行输出,输出两个实数x,y(保留小数点后两位),也就是你找到的建造基地的位置坐标。如果坐标不唯一,可以任选一个输出。
 
[align=left]Sample Input[/align]
41.0 1.03.0 1.03.0 3.01.0 3.00 
[align=left]Sample Output[/align]
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<stdio.h>
#include<algorithm>
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<stdio.h>
#include<algorithm>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: