关于网易内推编程题堆棋子的解法

第一题堆棋子,当场对角懵逼、拉格朗日懵逼、。。。然后就自然而然地跪了= =。心态很重要,心态炸了一切都完了。
后来跟室友讨论了一下,算是完整的找到了一个解法,然后上来翻帖子发现精品贴已经贴出来了,思路完全一样,但是缺少说明和证明,所以在这里补充一下。
首先得证明这么一个问题,当给定i个棋子的坐标后,最后全部汇聚到一个格子,使总移动步数最少,则这个格子的横坐标应该是所有i个棋子的横坐标的中位数,纵坐标应该是所有i个棋子的纵坐标的中位数(但是要注意该点不一定是i个点之一,这个比较容易被忽略)。室友提出来的,当时我就震惊了,膜拜一下室友。具体证明起来我表达能力较差,直接拋一个博客链接好了:http://blog.csdn.net/zhang20072844/article/details/13372753
曼哈顿距离有意思的地方就在于求和的时候可以把x和y解耦,然后分别考虑。退化到一维后,把上面链接中带权中位数的各权值设为1即可。文中给出的证明我没看(太长不看。。。),其实一维的问题画图很容易证明,给个思路:考虑第一个数和最后一个数的距离、第二个数和倒数第二个数的距离、...。
好了,上面的问题解决后,剩下的就相对简单了。不过有的人可能会想,既然给定i个点后汇聚点的坐标求法知道了,但是一共有n个点啊,选出i个点出来也相当麻烦呢,这里给出的回答是不用选。由于不管i取何值,以及怎么选出这i个点,最后的汇聚点的横坐标一定是n个点的横坐标之一,纵坐标一定是n个点的纵坐标之一,所以只需考虑这n*n种情况就可以了。这其实帮助我们把搜索目标从n个点的矩形包络的量级缩减到了n*n的量级。
最后,设一个有n*n行,n列的矩阵res,每一行存储n*n种汇聚点之一到n个点的曼哈顿距离,然后对每一行从小到大排序,然后逐行依次把第i列赋值为前i-1列数值之和。这时候的矩阵所存储的,其实是对于每一种汇聚点(对应每一行),把离其最近的i个点汇聚过来所需要的总步数。所以,最后的最后,对矩阵逐列求最小值,即为答案。
下面贴出C++的代码,变量命名一塌糊涂,见谅。。。(有一个优化策略,就是n个点的所有横坐标(以及纵坐标,道理一样)中,可能有重复值,这时只用选取一次即可,类似于求一个unique,但是对STL不太熟,就没做= =)
#include <iostream>
#include <algorithm>
using namespace std;

int main(){
    int n;
    cin>>n;
    int x[n];
    int y[n];
    for(int i=0;i<n;i++)
        cin>>x[i];
    for(int i=0;i<n;i++)
        cin>>y[i];
    int res[n*n][n];
    //计算n个点到n*n个候选目标点的距离
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            for(int k=0;k<n;k++){
                res[i*n+j][k] = abs(x[i]-x[k])+abs(y[j]-y[k]);
            }
    //对每个候选目标点到输入的n个点的距离排序(即对res的每一行排序)
    for(int i=0;i<n*n;i++)
        sort(*res+i*n,*res+(i+1)*n);
    //res的第i列,赋值为前i-1列之和,即距其最近的i个点移到该目标点的总移动次数
    for(int i=0;i<n;i++){
        if(i==0)
            continue;
        for(int j=0;j<n*n;j++){
            res[j][i]+=res[j][i-1];
        }
    }
    //求res每一列的最小值,即为答案
    for(int i=0;i<n;i++)
        for(int j=0;j<n*n-1;j++)
            res[0][i] = min(res[0][i],res[j+1][i]);
    for(int i=0;i<n;i++)
        i==0?cout<<res[0][i]:cout<<' '<<res[0][i];
    return 0;
}

#网易##算法工程师#
全部评论
赞一个
点赞 回复 分享
发布于 2017-08-13 14:34
棒棒!
点赞 回复 分享
发布于 2017-08-13 14:37
很明白!赞
点赞 回复 分享
发布于 2017-08-13 14:53
有个地方不明白,就是给出的博客链接上一下说n是奇数的时候取最中间两个值的平均数,一下又说取n/(2+1)
点赞 回复 分享
发布于 2017-08-13 15:33
厉害了,总是以为接近了答案  总是不对 现在终于明白了
点赞 回复 分享
发布于 2017-08-13 16:08
给赞  终于做出来了。
点赞 回复 分享
发布于 2017-08-13 16:54
点赞 回复 分享
发布于 2017-08-13 23:49
6666666666
点赞 回复 分享
发布于 2017-08-13 23:53

相关推荐

今天 17:22
已编辑
西安交通大学 Java
华为 ai软件开发 薪资20k x (14-16),职级13A,5%公积金,c/cpp
点赞 评论 收藏
分享
评论
点赞
收藏
分享
正在热议
# 25届秋招总结 #
439972次浏览 4484人参与
# 春招别灰心,我们一人来一句鼓励 #
41352次浏览 523人参与
# 北方华创开奖 #
107229次浏览 598人参与
# 地方国企笔面经互助 #
7914次浏览 18人参与
# 虾皮求职进展汇总 #
113497次浏览 880人参与
# 实习,投递多份简历没人回复怎么办 #
2453683次浏览 34846人参与
# 阿里云管培生offer #
119616次浏览 2219人参与
# 实习必须要去大厂吗? #
55552次浏览 959人参与
# 同bg的你秋招战况如何? #
75178次浏览 548人参与
# 提前批简历挂麻了怎么办 #
149763次浏览 1976人参与
# 投递实习岗位前的准备 #
1195578次浏览 18546人参与
# 你投递的公司有几家约面了? #
33165次浏览 188人参与
# 双非本科求职如何逆袭 #
661770次浏览 7394人参与
# 机械人春招想让哪家公司来捞你? #
157585次浏览 2267人参与
# 如果公司给你放一天假,你会怎么度过? #
4714次浏览 53人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11214次浏览 253人参与
# 发工资后,你做的第一件事是什么 #
12359次浏览 61人参与
# 工作中,努力重要还是选择重要? #
35521次浏览 384人参与
# 参加完秋招的机械人,还参加春招吗? #
20068次浏览 240人参与
# 实习想申请秋招offer,能不能argue薪资 #
39205次浏览 314人参与
# 我的上岸简历长这样 #
451863次浏览 8087人参与
# 非技术岗是怎么找实习的 #
155831次浏览 2120人参与
牛客网
牛客企业服务