U729328 开摆!(附加题)

题目背景

2026 赛季,队长看完比赛录像后拍板:我们要做轮腿平衡步兵。

理由很充分:普通步兵能过台阶吗?不能。能原地起跳躲弹吗?不能。别人家的轮腿在赛场上蹦跶得像个战神,我们家的步兵还在为一块 15° 的坡道写特殊判断。

于是机械组开始画五连杆,硬件组开始挑关节电机,而电控组面对的第一个问题就是——这玩意儿的控制核心,本质上就是一个倒立摆。

轮子往前滚,身子往后倒;轮子往后退,身子往前栽。陀螺仪的数据在串口屏上疯狂跳动,像极了你第一次调平衡车时的表情。LQR 的 Q 阵和 R 阵调了一版又一版,MATLAB 里的仿真曲线优美如画,一上实物车当场表演”滑铲入墙”。

队长深思熟虑后做出决定:新人在把倒立摆立起来之前,谁都不许碰真车。

“连一根杆都立不住,还想立一台二十公斤的车?”

现在,轮到你了。评测机里跑着一台简化的一阶倒立摆仿真——没有地滑,没有电机齿隙,没有 CAN 总线掉线,没有学长在旁边喊”让我看看”。这是最理想的环境,也是你成为电控组正式成员的第一道门槛。

立住它。然后去立那台真正的车。

你需要编写程序控制一个小车上的倒立摆,使其尽可能长时间保持不倒。

小车在一维轨道上运动,车上通过光滑铰链连接一根均质摆杆。每个控制周期你可以对小车施加一个水平方向的力 F,你需要根据当前状态决定 F 的大小。

g 重力加速度 9.8 m/s²

M 小车质量 1.0 kg

m 摆杆质量 0.1 kg

l 摆杆质心到转轴距离(半长) 0.5 m

Δt 控制周期 0.02 s

F_max 最大控制力 10.0 N

x_lim 小车位移上限 2.4 m

θ_lim 摆角上限 12°

T_max 最大步数 5000

题目描述

初始状态 x = 0,ẋ = 0,θ̇ = 0,θ 在 [−6°, 6°] 内由测试点种子随机生成。

失败条件 任一条件满足立即结束:

|θ| > θ_lim

|x| > x_lim

输出的 F 不是有限实数,或 |F| > F_max

交互协议

评测端与选手程序通过标准输入输出交互,每次输出后都必须刷新缓冲区。

重复以下过程:

评测端输出一行:x vx theta vtheta(4 个保留 6 位小数的实数)

选手读入该行,输出一行一个实数 F(施加的控制力)

评测端读入 F,积分一步

结束时,评测端输出一行:E steps(steps 为成功维持的步数),然后关闭。

每个测试点满分 10 分,维持 5000 步得满分,按步数线性给分。

输入格式

一行4个数,通过空格隔开

x vx theta vtheta

分别表示当前倒立摆的位置、速度、角度、角速度

输出格式

输出一行一个实数 F,表示施加的控制力

输入输出样例 #1

输入 #1

(无)

输出 #1

(无)

说明/提示

输入输出示例:

#include <iomanip>
#include <iostream>
 
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
 
    double x, vx, theta, vtheta;
 
    // 从评测端输入一轮状态。
    while (std::cin >> x >> vx >> theta >> vtheta) {
        // 这里只演示输出,不根据输入计算结果。
        // 每轮固定输出 0,并立即刷新,保证交互继续进行。
        std::cout << std::fixed << std::setprecision(10)
                  << 0.0 << std::endl;
    }
 
    return 0;
}