百度很有意思的一道面试题目

本文详细解析了一道经典的蚂蚁赛跑问题,通过等量代换思想解决了蚂蚁在细木杆上的移动问题,寻找所有蚂蚁离开木杆的最小时间和最大时间。

        找工作已经跑了一个多月,大大小小的笔试不记得参加了多少场,遇到最多的就是以下两种题目:数据结构和C++深入(尤其是虚函数)、智力题目。网易游戏的题目涉及到许多数学知识,搜狐游戏还好点,可惜死在最后一道题上了,关于贪心算法的一个应用(100分的题目这道题占了43分,晕死)。

        前几天福建IT企业组团来电子科大招聘,我看中了榕基软件,因为他们要招几个做网安产品研发的,我的简历应该让他们感到比较满意,问了很多问题,可惜第二天笔试的时候完全考砸了,一共就四道题目,第一题就是我们今天将要介绍的题目,详细介绍:有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。求所有蚂蚁都离开木杆的最小时间和最大时间。

        我苦思冥想了很久也没法算出最大时间,后面三道题做的也不是很顺利,只好无奈接受被淘汰的现实。回来后尝试搜索了一下,果然这道题已经出现过,而且百度的面试题目。

        以下答案是从网上搜索而来:

问题分析:
1.最小时间肯定是各自朝最近的一端跑,27-11=14,11<14,所以中间的蚂蚁会朝11cm那端跑,最小时短时间11。
2. 最长时间呢,肯定两端的蚂蚁都往中间跑,具体怎么跑好像有点儿想不清楚,那试算之,假设3cm处的和7cm处的相对而行,碰面后会怎样?如果你眼神不好,你会发现你分不出来哪个是哪个,因为3cm的转头后就相当于7cm的一直在走。到这里,一切就已经没有刚开始那样想不清楚了,事情很清楚:蚂蚁碰头可以用等量代换的思想,在这种情况下,任何蚂蚁都是自由地向它面向的一端直接爬过去。那最长时间就清楚了:27-3=24,27-23=4 24>23,所以最长时间是24。
有了以上分析,算法就简单了。
算法:
1.找出中间的蚂蚁离两端的距离中较小的。
a[2]=11
a[2]'=27-11=14,
因为a[2]<a[2]',所以最小距离是11,时间11/1=11
2.找出两端的蚂蚁距两端的距离中较大的。
a[0]=3
a[0]'=27-3=24
a[4]=23
a[4]'=27-23=4
这四个数中最大的是24。
3.所以,最大时间24,最小时间11
程序:略。

 

另外的分析,与上述介绍基本相同,但更加透彻易懂:关于这道题目,网上给出了很多的解释,但从整体来看,基本都是用到了等价置换(等量代换)的思想。要求最小时间,即为“最不容易”先到达两端的蚂蚁以最短的时间到达,所以我们只需找到所有蚂蚁中间的一只(共奇数只蚂蚁)或两只(共偶数只蚂蚁)到达一端的最短时间。比较麻烦的是求最长时间,有人会觉得当有很多只蚂蚁时,中间的蚂蚁们相互碰撞的次数多些会增加时间,感觉上比较复杂,可如果我们用等量代换的思想来解释就比较容易。假设中间的任意两只相邻蚂蚁即将发生碰撞,如:A ->         <-B,当A,B发生碰撞后,便有<-A     B->。A,B反向相当于<-B   A -> ,即二者继续向着原来的方向前进,对于任意相邻的发生碰撞的蚂蚁都适用,所以只需求最两端的两只蚂蚁距离两端的最远距离。由以上分析可知,如果出这样的问题,我们可以不用通过程序便能说出结果:5个点,中间蚂蚁的位置为11,即0-11-27,显然最小为11,最两端蚂蚁,0-3-27,最大为 24,0-23-27,最大为23,所以最大为24。

 

附Java解题程序(C语言写的话比较麻烦,C++懒得写):

public class Ant {
    //蚂蚁的位置
    private int position;
    //爬行方向
    private boolean front_flg;
    //是否到达终点
    private boolean isOver = false;
    //蚂蚁的名字
    private String antName;
    public boolean isOver() {
        if((position == 0)||(position == 27)){
            isOver = true;
        } else {
            isOver = false;
        }
        return isOver;
    }
    public void setOver(boolean isOver) {
        this.isOver = isOver;
    }
    public String getAntName() {
        return antName;
    }
    public void setAntName(String antName) {
        this.antName = antName;
    }
    public boolean isFront_flg() {
        return front_flg;
    }
    public void setFront_flg(boolean front_flg) {
        this.front_flg = front_flg;
    }
    public void setPosition(int position) {
        this.position = position;
    }
    //构造方法
    public Ant (int position,boolean flg,String antName){
        this.position = position;
        this.front_flg = flg;
        this.antName = antName;
    }
    public void crawl(boolean front_flg){
        //根据爬行方向判断position的加减
        if(!(isOver())){
            if (front_flg){
                position = position + 1;
            } else {
                position = position - 1;
            }
        }
        System.out.println(antName + " has arrived position : " + position);
    }
    public int getPosition() {
        return position;
    }
   
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Ant ant3 = new Ant (3,true,"ant3");
        Ant ant7 = new Ant (7,true,"ant7");
        Ant ant11 = new Ant (11,true,"ant11");
        Ant ant17 = new Ant (17,false,"ant17");
        Ant ant23 = new Ant (23,false,"ant23");
        //记录爬行时间
        int useTime = 1;
        while(!(ant3.isOver()
                &&ant7.isOver()
                &&ant11.isOver()
                &&ant17.isOver()
                &&ant23.isOver())){
           
            //如果两只蚂蚁相遇则调转爬行方向
            if (ant3.getPosition()==ant7.getPosition()){
                boolean temp;
                temp = ant3.isFront_flg();
                ant3.setFront_flg(ant7.isFront_flg());
                ant7.setFront_flg(temp);
            }
            if (ant3.getPosition()==ant11.getPosition()){
                boolean temp;
                temp = ant3.isFront_flg();
                ant3.setFront_flg(ant11.isFront_flg());
                ant11.setFront_flg(temp);
            }
            if (ant3.getPosition()==ant17.getPosition()){
                boolean temp;
                temp = ant3.isFront_flg();
                ant3.setFront_flg(ant17.isFront_flg());
                ant17.setFront_flg(temp);
            }
            if (ant3.getPosition()==ant23.getPosition()){
                boolean temp;
                temp = ant3.isFront_flg();
                ant3.setFront_flg(ant23.isFront_flg());
                ant23.setFront_flg(temp);
            }
           
            if (ant7.getPosition()==ant11.getPosition()){
                boolean temp;
                temp = ant7.isFront_flg();
                ant7.setFront_flg(ant11.isFront_flg());
                ant11.setFront_flg(temp);
            }
            if (ant7.getPosition()==ant17.getPosition()){
                boolean temp;
                temp = ant7.isFront_flg();
                ant7.setFront_flg(ant17.isFront_flg());
                ant17.setFront_flg(temp);
            }
            if (ant7.getPosition()==ant23.getPosition()){
                boolean temp;
                temp = ant7.isFront_flg();
                ant7.setFront_flg(ant23.isFront_flg());
                ant23.setFront_flg(temp);
            }
           
            if (ant11.getPosition()==ant17.getPosition()){
                boolean temp;
                temp = ant11.isFront_flg();
                ant11.setFront_flg(ant17.isFront_flg());
                ant17.setFront_flg(temp);
            }
            if (ant11.getPosition()==ant23.getPosition()){
                boolean temp;
                temp = ant11.isFront_flg();
                ant11.setFront_flg(ant23.isFront_flg());
                ant23.setFront_flg(temp);
            }
           
            if (ant17.getPosition()==ant23.getPosition()){
                boolean temp;
                temp = ant17.isFront_flg();
                ant17.setFront_flg(ant23.isFront_flg());
                ant23.setFront_flg(temp);
            }
            //蚂蚁爬行
            ant3.crawl(ant3.isFront_flg());           
            ant7.crawl(ant7.isFront_flg());           
            ant11.crawl(ant11.isFront_flg());           
            ant17.crawl(ant17.isFront_flg());           
            ant23.crawl(ant23.isFront_flg());           
            System.out.println("Use time is :" + useTime++);
            System.out.println("================================");
        }
    }
}

 

唉,从别人的解法中看到了自己的差距啊!!!

<think>嗯,用户想查找BUUCTF平台上的一道有趣题目的解题思路(wp)。这个问题需要结合用户提供的多个引用内容来回答,这些引用涵盖了Misc、RE、Crypto、Web等多个方向的题目解法片段。 首先注意到用户特别强调了"有趣"这个关键词。根据提供的引用内容,几个题目类型都挺有意思的:引用1提到BrainfuckOok语言加解密,引用2是迷宫题,引用5是个简单的栈溢出题。其中引用3的robots协议泄露源码题目比较特殊,涉及PHP反序列化SSRF漏洞利用,解题过程包含较多安全知识点,而且包含了源码分析、正则绕过、SSRF利用等层层递进的技巧。 准备从引用3的robots题目入手。引用3详细提供了源码内容,需要完整分析漏洞点:UserInfo类构造函数有参数注入风险;isValidBlog()方法使用正则校验URL格式,但容易被绕过;get()方法存在SSRF漏洞。解题思路可以分四步:访问robots.txt获取备份文件→分析源码→构造POP链→绕过URL验证读取flag。 还考虑在回答中补充两个相关问题:一个是关于正则绕过的变体思考,另一个是SSRF防御措施。这样既能满足用户获取解题思路的需,又能延伸相关知识点。 后检查引用标记的使用。在提到robots泄露时会引用[^3],在设计POP链利用SSRF时也会引用该源码内容。这样既保持了回答专业性,又确保所有引用来源都有明确标注。 </think>以下是BUUCTF中一道**设计巧妙且综合性较强**的题目(基于引用[3]的Web类题目)的完整解题思路: --- ### 题目:robots协议与PHP反序列化(Web类) #### 解题思路 **1. 发现源码泄露** 访问网站根目录下的 `robots.txt`,发现提示文件: ```http User-agent: * Disallow: /user.php.bak ``` 下载 `user.php.bak` 获取源码(引用[3])。 **2. 分析源码漏洞** 关键代码: ```php class UserInfo { public $name, $age, $blog; // ... public function getBlogContents() { return $this->get($this->blog); // 触发SSRF } public function isValidBlog() { return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $this->blog); } } ``` - **漏洞点1**:`isValidBlog()` 正则过滤可绕过(如 `http://127.0.0.1:80@evil.com` 会被解析为访问127.0.0.1)。 - **漏洞点2**:`getBlogContents()` 方法通过cURL发起请,存在**SSRF(服务端请伪造)**。 **3. 构造POP链利用反序列化** 目标:通过反序列化控制 `$blog` 属性,利用SSRF读取内网flag。 - 触发点:搜索源码中 `unserialize()` 的调用位置(题目通常通过Cookie、POST参数传入序列化数据)。 - 构造Payload: ```php <?php class UserInfo { public $blog = "gopher://127.0.0.1:80/_GET%20/flag.txt%20HTTP/1.1%0D%0AHost:%20127.0.0.1%0D%0A%0D%0A"; } echo serialize(new UserInfo); // 输出:O:8:"UserInfo":1:{s:4:"blog";s:58:"gopher://...";} ``` **4. 绕过URL正则校验** - 利用 `@` 符号混淆域名解析: `$blog = "http://127.0.0.1:80@example.com";` 正则校验通过,但cURL实际访问 `127.0.0.1:80`。 - 使用 `0://` 协议绕过(需环境支持): `$blog = "0://127.0.0.1:80/flag";` **5. 获取Flag** 将生成的序列化字符串提交至服务端(如通过Cookie),触发SSRF访问内网 `flag.txt`,响应中包含Flag。 --- ### 🔍 为什么此题有趣? 1. **多层知识点融合**: - robots协议 → 源码泄露 → 反序列化 → 正则绕过 → SSRF → 内网渗透 2. **经典漏洞组合**: 反序列化+SSRF是CTF Web题的常见套路,但结合URL解析特性设计绕过增加了挑战性。 3. **贴近实战**: 类似漏洞曾出现在真实CMS中(如Typecho反序列化漏洞CVE-2018-18753)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值