一道挺好玩的算法题,不知道各位有没有更好的想法 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
XiongZaizi
V2EX    算法

一道挺好玩的算法题,不知道各位有没有更好的想法

  •  
  •   XiongZaizi 2017-05-16 10:01:44 +08:00 4747 次点击
    这是一个创建于 3120 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小弟这几天在做算法题目,看到一个很 interesting 的题目,贴图如下: 题目

    简单描述下题目内容:这根木棍向右倒,在经过点 a 坐标之后,下一次在重合到一点时,输出离原点最近的那一点的坐标。 举个栗子:如下图

    栗子

    上图重合点是 5,3 这个点,接下来重合的点是 2,1 4,2 6,3 那么离原点最近的点就是 2,1。

    我的想法就是: 1、穷举出木棍 l 能扫过的所有的点,然后计算每个点到原点的距离,以及和横轴的夹角。按照角度进行快速排序;

    2、计算与点 a 重合时,木棍和横轴的夹角,抽取出小于该夹角的所有点

    3、对抽取出来的点按照距离进行一次遍历,找到距离原点最小的点进行输出

    总感觉这个算法有点复杂,不知道有没有更巧妙地算法?还请大家开动脑洞讨论讨论

    35 条回复    2017-05-16 22:55:15 +08:00
    grimpil
        1
    grimpil  
       2017-05-16 10:40:27 +08:00 via Android
    题目看不明白。点 a 是哪个点?重合到一点是什么意思?
    blankme
        2
    blankme  
       2017-05-16 10:48:21 +08:00 via Android
    建议贴原题,不要“简单描述题目内容”,你根本没描述清楚题目。
    yangff
        3
    yangff  
       2017-05-16 10:54:13 +08:00
    没理解错的话,没跨过(1,1)之前最近的是(1,1),跨过(x,1)之后最近的是(x+1,1);因为只需要考虑 gcd(x,y)==1 的点,所以扫过符合要求的 x 的时候,每个 x 显然能符合要求的最小的 y 是 1
    XiongZaizi
        4
    XiongZaizi  
    OP
       2017-05-16 11:01:35 +08:00
    @blankme 原题是日语的,我只能简单的进行翻译了。。。哪里不明白可以说一下
    jmc891205
        5
    jmc891205  
       2017-05-16 11:04:37 +08:00
    那些斜率一样的点只要记一个到原点距离最小的就可以了
    这样你的第一步快排之后就有了一个按斜率(角度)递增的数组
    之后只要拿 A 点的斜率做一次二分查找 找到的那个点的前一个点就是结果
    XiongZaizi
        6
    XiongZaizi  
    OP
       2017-05-16 11:04:49 +08:00
    @grimpil a 是随机输入的一个点,是棍子能够扫到的任何一点;重合到一点就是就是棍子在向下扫的时候,接触到的点。可以看第二个图,图中画的那条线就假设是棍子,在向下倒的时候,接触到了 5,3 这个点,这种情况就叫做重合
    Vinty
        7
    Vinty  
       2017-05-16 11:05:59 +08:00
    大概就是求一个比 a/b 小的最大的两个整数之比 x/y,x/y 有公约数,化简一下即可
    whalegia
        8
    whalegia  
       2017-05-16 11:08:27 +08:00
    重合是什么意思?
    为什么 ( 5,3 )后是( 2,1 ),( 2,1 )后是( 4,2 )?
    感觉我哪里都不明白,对不去语文老师
    XiongZaizi
        9
    XiongZaizi  
    OP
       2017-05-16 11:08:34 +08:00
    @jmc891205 有道理呢,这样能减少很大一部分的操作量了。多谢了
    XiongZaizi
        10
    XiongZaizi  
    OP
       2017-05-16 11:14:10 +08:00
    @whalegia 第二张图中实线是假设的棍子,这根棍子没有题目中的那么长,此时棍子接触到了点 5,3,棍子继续向下倒的时候,最先接触点 2,1,再接触点 4,2。
    Vinty
        11
    Vinty  
       2017-05-16 11:14:57 +08:00
    接 7l,这个值应该等于(ma-1)/(mb-1),m 是令该点在可行域内的最大整数
    XiongZaizi
        12
    XiongZaizi  
    OP
       2017-05-16 11:15:44 +08:00
    @yangff 那这样看来只有 y=1 的点是符合要求的,说的有道理
    XiongZaizi
        13
    XiongZaizi  
    OP
       2017-05-16 11:25:41 +08:00
    @Vinty “大概就是求一个比 a/b 小的最大的两个整数之比 x/y,x/y 有公约数,化简一下即可”,这一步是求出下一个杰出的点的吧?还有后面那个公式是咋计算的?
    liuminghao233
        14
    liuminghao233  
       2017-05-16 14:00:41 +08:00 via iPhone
    根本就不知道你在说什么 什么 a 点
    Vinty
        15
    Vinty  
       2017-05-16 14:37:41 +08:00
    @XiongZaizi 11l 的公式是我猜的,好像不对。。一是只考虑了小于 45°的情况,二是对可行域处理的不好。如果点的数量比较少的话,就列出可行域内的所有点按正切值做个排序就行了。如果是点非常复杂的话,那就找到目前过( a,b )这条线和边界的交点( u,v ),向下取整得到( u',v')。比较( u',v'),( u'+1,v'),( u',v'-1 ),( u'+1,v'-1 )四点即可,也许还有( u'-1,v'-1 )。
    反正就是比较周围几个点看在不在可行域内哪个最大,具体哪几个也许可以简化一下。
    imn1
        16
    imn1  
       2017-05-16 15:16:55 +08:00
    下一次在重合到一点时,输出离原点最近的那一点的坐标
    -------------------------------------------------------------------------
    这句话是要再解释清楚的

    “下一次在重合到一点时”,换言之,重合 A 到这次重合中间没有再重合任何点了,下半句“那一点”指的是什么?
    lingo
        17
    lingo  
       2017-05-16 18:04:39 +08:00
    哈哈哈哈哈题目看不懂
    XiongZaizi
        18
    XiongZaizi  
    OP
       2017-05-16 18:10:40 +08:00
    @Vinty 恩恩,谢谢了,这样也是一种方法
    XiongZaizi
        19
    XiongZaizi  
    OP
       2017-05-16 18:16:41 +08:00
    @imn1 就是棍子在向下倒的这个过程中,会接触到点格中的点,那么假设其中有一时刻棍子和给定的能够接触到的点 a 接触了记为时刻 t1,从这一时刻起开始,棍子继续向下倒,又会接触一个新的点 b,时刻记为 t2。这 t1 和 t2 两个时刻之间,棍子没有和任何的点接触。所要求的就是从 t1 时刻开始,到棍子最终倒在横轴上这一段时间里,棍子所能接触到的所有点中,距离原点最小的一点。
    ZyZyZzz
        20
    ZyZyZzz  
       2017-05-16 18:24:47 +08:00
    你直接把日语题干贴出来吧,这里有的是人懂日语
    不懂的还可以去机翻
    GtDzx
        21
    GtDzx  
       2017-05-16 18:36:57 +08:00
    感觉就是个排序题。按极角和距离排序不就完了...
    hxsf
        22
    hxsf  
       2017-05-16 18:38:15 +08:00 via iPhone
    有意思的题目。
    回家电脑码字
    imn1
        23
    imn1  
       2017-05-16 18:55:57 +08:00
    A(x0, y0)
    棍长 s0
    所经过的点 Pn(xn, yn)

    Pn 满足
    Xn<=S0 && Yn/Xn 反正切的角度<Y0/X0 反正切角度

    Pn 到原点距离 Sn
    Sn^2 = Xn^2 + Yn^2 = (Xn + Yn)^2 - 2*Xn*Yn
    所以,Xn + Yn 最小值为所求
    当有两点或以上满足此条件时,Xn 与 Yn 数值最接近的为所求
    blankme
        24
    blankme  
       2017-05-16 19:36:28 +08:00 via Android
    y = 1
    x = min(n), where arctan(1 / n) < arctan(y0 / x0)
    hxsf
        25
    hxsf  
       2017-05-16 19:43:07 +08:00
    到家,开更。

    最暴力的方法,算一下每个点的角坐标(θn, ln),排除掉 ln > l 棍 和 角度小于 点 a 的,然后根据θn 排序。取第一个。

    ==========================当然不是这么简单啦==============================

    我们真的需要算这么多点么?

    其实我们要算的,只有 线段 OA 附近的点啊。( O 指原点,A 点坐标设为( a,b ))

    OA 附近的点(记为集合 D )如何得出?

    D 中的[ (x1, y1),(x2, y2),……(xn, yn)] 满足

    1. x 属于 0~Xmax 上的所有整数
    由数学方案可知,Xmax = a * 根号( L 棍^2 - a^2 - b^2 ), 及 n = int ( Xmax )
    2. 因为要找 yn/xn 尽可能大的,所以 yn < xn * b/a 的基础上, yn > yn-1 + 1

    于是要计算的点就变成这样:



    完结!
    hxsf
        26
    hxsf  
       2017-05-16 19:45:08 +08:00
    @hxsf #25

    更正

    >>>>>>>>>>
    2. 因为要找 yn/xn 尽可能大的,所以 yn < xn * b/a 的基础上, yn > yn-1 + 1
    ==========
    2. 因为要找 yn/xn 尽可能大的,所以 yn < xn * b/a 的基础上, yn > yn-1
    <<<<<<<<<<

    忘记说了。红色点是要算的点,蓝色点是 满足 yn < xn * b/a 但不满足 yn > yn-1
    XiongZaizi
        27
    XiongZaizi  
    OP
       2017-05-16 21:05:53 +08:00
    @imn1 那这样还是要穷举计算出所有的点,感觉如果 l 很大的话计算量会很多
    XiongZaizi
        28
    XiongZaizi  
    OP
       2017-05-16 21:17:14 +08:00
    @hxsf 学习了。但是我有点没有明白 xmax 的计算公式是怎样得到的?
    hxsf
        29
    hxsf  
       2017-05-16 21:25:04 +08:00   1
    @XiongZaizi #28

    你一说发现算错了。。。尴尬

    下面是正确算法

    棍子与 A(a, b)重合时的 端点 B 设为 (na, nb)

    (na)^2 + (nb)^2 = l^2

    就可以算出来了 n^2 = l^2 / (a^2 + b^2)

    na = a * 根号( l^2 / (a^2 + b^2) )
    XiongZaizi
        30
    XiongZaizi  
    OP
       2017-05-16 21:30:22 +08:00
    @hxsf 哦哦哦,明白了,是按照比例算的。按照你的方法,可以减少很多计算量,多谢!!!
    XiongZaizi
        31
    XiongZaizi  
    OP
       2017-05-16 21:33:29 +08:00
    imn1
        32
    imn1  
       2017-05-16 21:57:49 +08:00
    @XiongZaizi
    怎么需要穷举所有点呢?

    所有的点都是已知坐标的吧?
    从最小值开始计算角度是否符合就够了
    如果是要尽可能大,就从 Xn<=S0 最大值开始,只要(Xn_1<Xn && Yn_1<Yn)符合就可以结束了
    bumz
        33
    bumz  
       2017-05-16 22:00:07 +08:00
    @XiongZaizi #31 这是什么书呀
    XiongZaizi
        34
    XiongZaizi  
    OP
       2017-05-16 22:53:44 +08:00
    @imn1 啊,有理。一时没转过弯来
    XiongZaizi
        35
    XiongZaizi  
    OP
       2017-05-16 22:55:15 +08:00
    @bumz 基友正在看的书,我也不知道叫啥。今天偶然开始讨论起来的题目。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     844 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 19:26 PVG 03:26 LAX 11:26 JFK 14:26
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86