提问人:Francisco José Letterio 提问时间:4/26/2023 更新时间:4/26/2023 访问量:45
CIN 一遍又一遍地读取相同的值
cin stuck reading the same value over and over
问:
我正在尝试解决以下问题: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 的相同值
老实说,我完全迷路了。我不知道这里发生了什么,在过去的一个小时里,我一直在用头撞墙试图解决这个问题
答:
你似乎认为,如果你这样做了,并且没有什么可读的,将被设置为.但实际上,让我们来看看什么是:std::cin >> m >> n;
cin
m
0
operator>>
basic_istream& operator>>( unsigned int& value ); (2)
1-11) 提取可能跳过前面空格的值。该值将存储到给定的引用中。
value
此函数的行为方式为 FormattedInputFunction。构造并检查 sentry 对象(可能会跳过前导空格)后,通过调用 来提取值。
std::num_get::get()
如果 FormattedInputFunction 无法读取,它会怎么做?
FormattedInputFunction 是一个流输入函数,它执行以下操作:
- 构造一个类型为 basic_istream::sentry 的对象,该对象具有自动存储持续时间,并将 noskipws 参数设置为 false,该对象将执行以下操作
- 如果在输入流上设置了 或,则设置 ,如果在此输入流的异常掩码 () 中启用了异常,则会抛出 。
eofbit
badbit
failbit
failbit
(exceptions() & failbit) != 0
ios_base::failure
- 刷新 'd 输出流(如果适用)
tie()
- 如果在此输入流上设置了标志,则从输入流中提取并丢弃字符,直到满足以下条件之一:
ios_base::skipws
- 输入流上的下一个可用字符不是空格字符,这是由当前填充在此输入流中的区域设置的方面测试的。不提取非空格字符。
std::ctype
- 到达流的末尾,在这种情况下,设置了 和 ,如果流因其中一个位上的异常而打开,则抛出。
failbit
eofbit
ios_base::failure
- 通过调用 来检查哨兵的状态,相当于 。
sentry::operator bool()
basic_ios::good
- 如果哨兵返回或哨兵的构造函数抛出异常,则不会发生任何输入
false
强调是后加的。如果没有什么可读的,它就不管了。所以在一次失败的读取之后,仍然是,不是,所以仍然是。std::cin >> m
m
m
11
0
while(m)
true
关于上述内容的说明:在某些情况下,读取失败会导致设置为 。如果流中确实有可供读取的数据,但此数据无法在步骤中转换为整数:std::cin >> m
m
0
std::num_get::get()
如果转换函数无法转换整个字段,则该值将存储在 中。
0
v
推荐的方法是直接检查读取本身是否成功。因此,与其在后面检查 的值,不如将循环写为std::cin >> m >> n;
m
while(std::cin >> m >> n)
{
// Do stuff...
}
这依赖于这样一个事实,即有一个运算符 bool,该运算符指示最近的流操作是否成功。这样,所有读取失败都会得到统一处理。std::istream
cin
评论
while (std::cin >> m >> n) { ... }
是处理这个问题的正确方法。