c++ cin坚持一遍又一遍地阅读相同的值

5anewei6  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(109)

我正在尝试解决以下问题: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重复相同的值
我真的完全迷路了。我完全不知道这是怎么回事过去的一个小时里我一直在用头撞墙试图解决这个问题

9gm1akwq

9gm1akwq1#

您似乎认为,如果执行std::cin >> m >> n;,而cin没有任何内容可读取,则m将被设置为0。但实际上,让我们来看看operator>>是做什么的:
operator>>(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,它执行以下操作
  • 如果在输入流上设置了eofbitbadbit,则也设置failbit,如果在此输入流的异常掩码((exceptions() & failbit) != 0)中启用了failbit上的异常,则抛出ios_base::failure
  • 刷新tie()的输出流(如果适用)
  • 如果在此输入流上设置了ios_base::skipws标志,则从输入流中提取并丢弃字符,直到以下其中一项变为真:
  • 输入流上的下一个可用字符不是空白字符,如由当前灌输在该输入流中的区域设置的X1 M15 N1 X方面所测试的。不提取非空白字符。
  • 到达流的末尾,在这种情况下,设置failbiteofbit,并且如果流由于这些位之一上的异常而打开,则抛出ios_base::failure
  • 通过调用sentry::operator bool()(相当于basic_ios::good)检查哨兵的状态。
  • 如果sentry返回false或sentry的构造函数抛出异常,不发生任何输入

重点已添加。如果std::cin >> m没有任何可读取的内容,它将不读取m。因此,在读取失败后,m仍然是11,而不是0,因此while(m)仍然是true
关于上述内容的说明:在某些情况下,读取std::cin >> m失败会导致m被设置为0。如果流中确实有数据可供读取,但此数据无法在std::num_get::get()步骤中转换为整数:
std::num_get::get
如果转换函数无法转换整个字段,则值​0 存储在v中。
推荐的方法是直接检查读取本身是否成功。因此,不需要在std::cin >> m >> n;之后检查m的值,而是将循环编写为

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

这依赖于std::istream有一个operator bool来指示最近的流操作是否成功。这样,所有从cin读取的失败都会被统一处理。

相关问题