B. Chess Cheater

这篇博客介绍了如何运用贪心策略解决一个棋盘得分优化问题。给定一个由赢(W)和输(L)组成的字符串,目标是在最多修改k个位置的情况下,最大化得分。算法首先确保尽可能多的连续胜利,并优先修改非连续的失败场次。通过特殊处理首尾输的情况和对输掉的场次排序,找到最有利的修改方案,从而求得最高可能的得分。

B. Chess Cheater
题意
给了你一个字符串,'W’表示赢,‘L’表示输,赢可以加1分,如果赢的前一场也是赢,那么此时可以加两份,现在你可以修改k个地方,问你最高的分数。
思路
贪心
首先我们肯定是保证连胜的场次越多越好,最好是全部都能够赢,但是收到了k的限制,所以我们应该优先让两个’W’之间的’L’变为’W’,这样我们就可以制造尽可能多的连胜。那么假设现在我们知道了胜利的场次,怎样计算分数呢?假设现在胜利的场次为win,假设我们每一场都能够获得两分,那么现在的分数就是2*win,但是有些不是连续的,现在我们要记录不是连续的的场次,我们设没有连胜的场次为cnt_str,那么这里有两种情况:i == 0 || s[i - 1] == 'L',这这两种情况下,都属于不是连胜的,那么我们最终的得分就是2×win - cnt_str。
那么接下来我们要找输掉了的场次,对于输掉了的场次也要分情况:首先我们要记录输掉了的场次,还要判断连输的场次,因为我们后面在修改场次的时候都是优先修改不是连输的、连输少的,这样贪的结果才是最优的。
接下来我们对于第一场和最后一场要进行特判,如果这两个位置都是输的话,我们要把它们放到最后,然后进行排序,(见代码);

#include <bits/stdc++.h>

using namespace std;

const int inf = 0x3f3f3f3f;

void solve()
{
    int n, k; cin >> n >> k;
    string s; cin >> s;

    int win = 0, los = 0, win_str = 0;
    vector<int> los_str;

    for (int i = 0; i < n; i ++)
    {
        if (s[i] == 'W')
        {
            if (i == 0 || s[i - 1] == 'L') win_str ++;
            win ++;
        }
        else
        {
            los ++;
            if (i == 0 || s[i - 1] == 'W') los_str.push_back(0);
            los_str.back() ++;
        }
    }

    if (k >= los) { cout << 2 * n - 1 << endl; return; }
    if (win == 0)
    {
        if (k == 0) cout << 0 << endl;
        else cout << 2 * k - 1 << endl;
    }

    if (s[0] == 'L') los_str[0] = inf;
    if (s[n - 1] == 'L') los_str.back() = inf;

    sort(los_str.begin(), los_str.end());

    int len = los_str.size();
    win += k;

    for (int i = 0; i < len; i ++)
    {
        if (los_str[i] > k) break;
        else { win_str --; k -= los_str[i]; }
    }

    cout << 2 * win - win_str << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int t; cin >> t;
    while (t --) solve();

    return 0;
}

<think>嗯,用户给了一段numpy的代码,想要理解它的工作原理。我需要先仔细看看这段代码的结构,然后逐步拆解每个部分的作用。 首先,代码有两行: 1. `objp = np.zeros((1, self.chess[0] * self.chess[1], 3), dtype=np.float32)` 2. `objp[0, :, :2] = np.mgrid[0:self.chess[0], 0:self.chess[1]].T.reshape(-1, 2)` 先看第一行,创建了一个三维数组,形状是(1, chess[0]*chess[1], 3),类型是float32。这里的self.chess应该是一个棋盘格的行列数,比如像OpenCV中的棋盘角点检测,可能chess[0]是行数,chess[1]是列数。所以这个数组可能是用来存储棋盘格每个角点的三维坐标。初始化为零,第三维有3个元素,可能对应x,y,z坐标,但因为是平面棋盘,z可能都是0。 第二行,将objp的第0个元素的第三维的前两个(:2)赋值。右边用到了np.mgrid,生成从0到chess[0]和0到chess[1]的网格。mgrid返回的是密集网格,比如如果chess是(5,7),那么mgrid[0:5, 0:7]会生成两个二维数组,分别是x坐标和y坐标。然后转置.T,可能交换了行列,再reshape成(-1,2),把网格点展开成二维数组,每行是一个点的坐标。这样赋值给objp的前两维,也就是x和y,z保持0。 最终,objp应该是一个三维点数组,每个点对应棋盘格的一个角点,x和y是网格中的位置,z为0。这在相机标定中用来生成世界坐标系中的角点位置,假设棋盘在z=0平面。 需要确认mgrid的用法是否正确。比如,mgrid[0:a, 0:b]会生成形状为(2,a,b)的数组,转置后变成(b,a,2),然后reshape成(-1,2)后变成(b*a, 2)的形状。比如,如果chess是(6,9),则生成54个点,每个点的坐标是(0,0),(0,1),...,(5,8)。这样赋值给objp的前两维,第三维的z保持0。这样每个角点的世界坐标就是(x, y, 0),符合棋盘平面在z=0的情况。 用户可能是在做相机标定,所以这段代码是生成物体点的坐标,也就是标定板上的实际坐标。需要解释清楚每个步骤的作用,比如np.zeros创建数组,mgrid生成网格,reshape调整形状,以及最终的数据结构。 另外,用户可能对numpy的数组操作不太熟悉,比如mgrid、转置、reshape的作用,需要详细说明这些函数的结果如何变化,以及为什么这样做。例如,为什么要转置,可能因为生成的网格坐标需要按行优先或列优先排列,而OpenCV的角点检测顺序可能与mgrid默认的生成方式不同,所以需要调整。 还要注意代码中的self.chess可能是一个元组,比如(CHECKERBOARD_ROWS, CHECKERBOARD_COLS),所以在生成网格时,0到self.chess[0]和0到self.chess[1]的范围是否正确?比如,如果棋盘有6行9列,角点坐标应该是0到5和0到8,对吗?是的,因为mgrid的结束是不包含的,所以0:self.chess[0]会生成0到self.chess[0]-1的值,符合角点的索引。 总结一下,这段代码的作用是创建一个三维数组,用来存储棋盘格每个角点的三维坐标,其中x和y坐标按网格排列,z坐标为0,适用于相机标定中的物体坐标系设定。需要分步骤解释每个函数的作用,以及最终的数据结构。</think>### 代码解析 #### 1. 初始化三维坐标数组 ```python objp = np.zeros((1, self.chess[0] * self.chess[1], 3), dtype=np.float32) ``` - **作用**:创建一个形状为 $1 \times (m \cdot n) \times 3$ 的三维数组,其中 $m = \text{self.chess[0]}$(棋盘行数),$n = \text{self.chess[1]}$(棋盘列数),第三维度存储 $(x, y, z)$ 坐标[^1]。 - **细节**: - `dtype=np.float32` 确保数据精度符合图像处理要求。 - 初始 $z$ 值为 0,因为棋盘默认在 $z=0$ 平面。 #### 2. 生成网格坐标并赋值 ```python objp[0, :, :2] = np.mgrid[0:self.chess[0], 0:self.chess[1]].T.reshape(-1, 2) ``` - **作用**:为棋盘角点生成 $(x, y)$ 坐标,覆盖所有行列组合。 - **分步解析**: 1. **`np.mgrid`**:生成密集网格坐标,输出形状为 $2 \times m \times n$ 的数组,包含 $x$ 和 $y$ 方向的值。 - 例如,若 `self.chess=(3,2)`,则输出: $$x = \begin{bmatrix}0 & 0 \\ 1 & 1 \\ 2 & 2\end{bmatrix}, \quad y = \begin{bmatrix}0 & 1 \\ 0 & 1 \\ 0 & 1\end{bmatrix}$$ 2. **`.T`**:转置后形状变为 $n \times m \times 2$,使坐标按行列顺序排列。 3. **`reshape(-1, 2)`**:将网格展平为 $(m \cdot n) \times 2$ 的二维数组,每行对应一个角点的 $(x, y)$。 4. **赋值**:将生成的坐标填入 `objp` 的第一个维度的前两列(`x` 和 `y`)。 #### 最终结果 - **数据结构**:`objp` 是一个三维数组,形状为 $1 \times (m \cdot n) \times 3$。 - **内容示例**(假设 `self.chess=(2,2)`): $$ \text{objp} = \begin{bmatrix} [(0,0,0), (0,1,0), (1,0,0), (1,1,0)] \end{bmatrix} $$ ### 应用场景 此代码常用于**相机标定**,为棋盘角点生成理论上的三维世界坐标,用于与图像中的二维像素坐标匹配。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值