CIN 一遍又一遍地读取相同的值

cin stuck reading the same value over and over

提问人:Francisco José Letterio 提问时间:4/26/2023 更新时间:4/26/2023 访问量:45

问:

我正在尝试解决以下问题:https://onlinejudge.org/index.php?option=onlinejudge&Itemid=8&page=show_problem&problem=3693

这是我的代码:

#include <algorithm>
#include <functional>
#include <iostream>
#include <utility>
#include <vector>
#include <map>
#include <limits>

typedef unsigned int ui;

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

    ui m,n;
    std::cin >> m >> n;
    while(m){
        std::vector<int> objects(n);
        for(auto i = 0u; i < n; i++){
            std::cin >> objects[i];
        }

        //memoizacion
        std::map<std::pair<ui, ui>, ui> mem;

        std::function<ui(std::pair<ui, ui>)> question = [&](std::pair<ui, ui> set) -> ui {
            if(!mem.count(set)){
                int inSet = 0;
                for(auto i = 0u; i < n; i++){
                    if(((objects[i] & set.first) == set.first) and (((~objects[i]) & set.second) == set.second))
                        inSet++;
                }
                if(inSet <= 1) mem.insert(std::pair<std::pair<ui, ui>, ui>(set, 0));
                else {
                    ui min = std::numeric_limits<ui>::max();
                    for(auto k = 1u, i = 0u; i < m; i++, k <<= 1){
                        if(!(k & set.first) and !(k & set.second)){
                            ui candidate = std::max(question(std::pair<ui,ui>(set.first | k, set.second)),
                                                    question(std::pair<ui, ui>(set.first, set.second | k)));
                            min = min < candidate ? min : candidate;
                        }
                    }
                    mem.insert(std::pair<std::pair<ui, ui>, ui>(set, min + 1));
                }
            }
            return mem.at(set);
        };

        std::cout << question(std::pair<ui, ui>(0,0)) << "\n";

        std::cin >> m >> n;
    }
}

当我使用示例输入运行此代码时(在链接中详细说明问题的 pdf 上),我的代码解决了前两种情况,然后在第三种情况下进入无限循环

当我用调试器检查它时,我注意到该行

std::cin >> m >> n;

是导致错误的原因。在阅读了第三个案例后,当它试图再次阅读时,它什么也没做。一旦达到 m = 11, n = 16 的情况,m 和 n 保持不变。就像它被一遍又一遍地调用一样(因为循环结束的条件是 m 为 0),但它不是读取下一个输入,而是卡在那里,重复 m 和 n 的相同值

老实说,我完全迷路了。我不知道这里发生了什么,在过去的一个小时里,我一直在用头撞墙试图解决这个问题

C++ IOstream

评论

3赞 Retired Ninja 4/26/2023
while (std::cin >> m >> n) { ... }是处理这个问题的正确方法。

答:

2赞 Nathan Pierson 4/26/2023 #1

你似乎认为,如果你这样做了,并且没有什么可读的,将被设置为.但实际上,让我们来看看什么是:std::cin >> m >> n;cinm0operator>>

运算符>>(std::basic_istream)

basic_istream& operator>>( unsigned int& value ); (2)

1-11) 提取可能跳过前面空格的值。该值将存储到给定的引用中。value

此函数的行为方式为 FormattedInputFunction。构造并检查 sentry 对象(可能会跳过前导空格)后,通过调用 来提取值。std::num_get::get()

如果 FormattedInputFunction 无法读取,它会怎么做?

FormattedInputFunction 是一个流输入函数,它执行以下操作:

  • 构造一个类型为 basic_istream::sentry 的对象,该对象具有自动存储持续时间,并将 noskipws 参数设置为 false,该对象将执行以下操作
    • 如果在输入流上设置了 或,则设置 ,如果在此输入流的异常掩码 () 中启用了异常,则会抛出 。eofbitbadbitfailbitfailbit(exceptions() & failbit) != 0ios_base::failure
    • 刷新 'd 输出流(如果适用)tie()
    • 如果在此输入流上设置了标志,则从输入流中提取并丢弃字符,直到满足以下条件之一:ios_base::skipws
      • 输入流上的下一个可用字符不是空格字符,这是由当前填充在此输入流中的区域设置的方面测试的。不提取非空格字符。std::ctype
      • 到达流的末尾,在这种情况下,设置了 和 ,如果流因其中一个位上的异常而打开,则抛出。failbiteofbitios_base::failure
  • 通过调用 来检查哨兵的状态,相当于 。sentry::operator bool()basic_ios::good
  • 如果哨兵返回或哨兵的构造函数抛出异常,则不会发生任何输入false

强调是后加的。如果没有什么可读的,它就不管了。所以在一次失败的读取之后,仍然是,不是,所以仍然是。std::cin >> mmm110while(m)true


关于上述内容的说明:在某些情况下,读取失败会导致设置为 。如果流中确实有可供读取的数据,但此数据无法在步骤中转换为整数:std::cin >> mm0std::num_get::get()

std::num_get::get

如果转换函数无法转换整个字段,则该值将存储在 中。​0v


推荐的方法是直接检查读取本身是否成功。因此,与其在后面检查 的值,不如将循环写为std::cin >> m >> n;m

while(std::cin >> m >> n)
{
  // Do stuff...
}

这依赖于这样一个事实,即有一个运算符 bool,该运算符指示最近的流操作是否成功。这样,所有读取失败都会得到统一处理。std::istreamcin