1 条题解

  • 0
    @ 2025-11-26 15:15:31

    题目分析

    这是一个交互式问题,需要在网格中找到宝箱的位置。关键约束是:

    • 宝箱会阻挡机器人移动
    • 每次查询后机器人回到起点
    • 需要在最少次查询内确定宝箱位置

    算法思路

    核心思想

    使用两次查询策略

    1. 第一次查询:水平移动探测,快速确定宝箱是否在右侧路径上
    2. 第二次查询:复杂蛇形路径,精确定位宝箱位置

    关键观察

    • 如果宝箱不在机器人移动路径上,机器人会到达预期位置
    • 如果宝箱在路径上,机器人会被阻挡,最终位置会暴露宝箱信息
    • 通过精心设计路径,可以在两次查询内唯一确定宝箱位置

    代码详解

    交互函数

    pair<int,int> ask(string s){
        cout<<"? "<<s<<'\n';
        fflush(stdout);
        int x,y;
        cin>>x>>y;
        return make_pair(x,y);
    }
    

    第一次查询:水平探测

    string s = "";
    for(int i = 0; i < m; i++) s += ">";  // 构造纯右移指令
    auto v = ask(s);
    
    // 如果机器人没有到达最右端,说明宝箱在水平路径上
    if(v.S != m - 1){
        cout<<"! "<<v.F<<" "<<v.S + 1<<'\n';
        return 0;
    }
    

    逻辑

    • 如果宝箱在 (r, c)c < m-1,机器人会在宝箱前一格停止
    • 最终位置直接给出宝箱的列坐标:v.S + 1
    • 行坐标就是机器人停止的行:v.F

    第二次查询:蛇形路径探测

    s = "v";  // 先向下移动一格
    for(int i = 1; i < n; i++){
        for(int j = 0; j < m; j++) s += ">";  // 向右移动到底
        s += "^>v";  // 向上、右、下(形成Z字形)
        for(int j = 0; j < m; j++) s += "<";  // 向左移动到底
        s += "v";    // 向下移动
    }
    for(int i = 0; i < m; i++) s += ">";  // 最后向右移动到底
    
    v = ask(s);
    

    位置推断逻辑

    if(v.S == m - 1){
        // 到达最右列,说明宝箱在第一列
        if(v.F == n - 1) v.F = 0;  // 边界处理
        cout<<"! "<<v.F + 1<<" "<<0<<'\n';
    } else {
        // 未到达最右列,根据最终位置推断宝箱位置
        cout<<"! "<<v.F<<" "<<v.S + 1<<'\n';
    }
    

    算法原理

    路径设计分析

    第二次查询的路径设计:

    1. 起始v - 向下移动,避开 (0,0) 起点
    2. 循环结构:对于每行 i(从1到n-1):
      • >>>... - 向右移动到底
      • ^>v - 向上、右、下,形成Z字转折
      • <<<... - 向左移动到底
      • v - 向下移动
    3. 结束>>>... - 最后向右移动到底

    为什么这样能确定所有位置?

    • 宝箱在内部:会被蛇形路径探测到,机器人停止位置指示宝箱坐标
    • 宝箱在第一列:只有这种情况机器人能到达最右端
    • 宝箱在最后位置:特殊边界条件处理

    复杂度分析

    查询次数

    • 最优情况:1次查询(宝箱在水平路径上)
    • 最坏情况:2次查询
    • 满足得分公式要求:Q2Q \leq 2 可得100分
    • 1

    信息

    ID
    5590
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者