这是著名逻辑学家走在酒吧谜语中的代码(问题 - https://www.codechef.com/problems/LOGICIAN) 这是我的代码:
#include <iostream>
using namespace std;
int main() {
// your code goes here
int T;
cin >> T;
for(int i=0;i<T;i++){
int N;
cin >> N;
char beer[N];
cin >> beer;
int idk=1;
for(int j=0;j<(N-1);j++){
if(beer[j]=='1' && idk==1){cout << "IDK" << endl;}
if(beer[j]=='1' && idk!=1){cout << "NO" << endl;}
if(beer[j]=='0'){cout << "NO" << endl;idk=0;}
}
if(beer[N-1]=='1' && idk==1){cout << "YES" << endl;}
if(beer[N-1]=='1' && idk!=1){cout << "NO" << endl;}
if(beer[N-1]=='0' ){cout << "NO" << endl;}
}
return 0;
}
我的测试用例出现运行时错误,否则它工作正常。
所以,这真是一个谜。 据我所知,您的代码存在一些风格问题,但是正确的。它应该有效。我将在接下来的几行中证明这一点。
让我们开始研究内循环:
if(beer[j]=='1' && idk==1){cout << "IDK" << endl;}
if(beer[j]=='1' && idk!=1){cout << "NO" << endl;}
if(beer[j]=='0'){cout << "NO" << endl;idk=0;}
由于
idk
被视为布尔值,我宁愿选择:
if (idk == 1) {
if (beer[j]=='1') {
cout << "IDK" << endl;
} else {
cout << "NO" << endl;
idk = 0;
}
} else {
cout << "NO" << endl;
}
让我们证明它与您的代码完全等效。如果提取出四种可能的执行路径(假设
beer[j]
只能是'0'
或'1'
),你会得到:
if (idk == 1 && beer[j]=='1') { cout << "IDK" << endl; }
if (idk == 1 && beer[j]=='0') { cout << "NO" << endl; idk=0; }
if (idk != 1 && beer[j]=='1') { cout << "NO" << endl; }
if (idk != 1 && beer[j]=='0')) { cout << "NO" << endl; }
与之前有一个细微的差别:第一次之后,
idk
没有在 0
上设置为 beer[j]=='0'
- 但这当然在逻辑上不相关:我们可以在所有分支中将 idk
设置为 0
,其中已经是!=1
,对结果没有影响。让我们来做吧:
if (idk == 1 && beer[j]=='1') { cout << "IDK" << endl; }
if (idk == 1 && beer[j]=='0') { cout << "NO" << endl; idk=0; }
if (idk != 1 && beer[j]=='1') { cout << "NO" << endl; idk=0; } // idk=0; does nothing
if (idk != 1 && beer[j]=='0')) { cout << "NO" << endl; idk=0; } // idk=0; does nothing
您现在可以将第二行和最后一行折叠为一个条件:
if (idk == 1 && beer[j]=='1') { cout << "IDK" << endl; }
if (idk != 1 && beer[j]=='1') { cout << "NO" << endl; idk=0; }
if (beer[j]=='0') { cout << "NO" << endl; idk=0; } // collapsed 2nd and 4th lines
现在,再次将
idk
设置为 0
,它已经是 !=1
不会产生任何效果...所以我们可以在第二行停止这样做。
if (idk == 1 && beer[j]=='1') { cout << "IDK" << endl; }
if (idk != 1 && beer[j]=='1') { cout << "NO" << endl; } // removed useless statement
if (beer[j]=='0') { cout << "NO" << endl; idk=0; }
对于
&&
运算符的交换性,这与代码中的内容相同。
现在,让我们在外部进行相同的重构,这将导致我们得到这个完整的解决方案:
#include <iostream>
using namespace std;
int main() {
// your code goes here
int T;
cin >> T;
for(int i=0;i<T;i++){
int N;
cin >> N;
char beer[N];
cin >> beer;
int idk=1;
for(int j=0;j<(N-1);j++){
if (idk==1) {
if (beer[j] == '1') {
cout << "IDK" << endl;
} else {
cout << "NO" << endl;
idk = 0;
}
} else {
cout << "NO" << endl;
}
}
if (idk==1) {
if (beer[N-1] == '1') {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
} else {
cout << "NO" << endl;
}
}
return 0;
}
好吧,如果你现在运行它......它就会通过!
就我所见,要么存在一些我没有得到的细微差别(在编译/执行方式方面,而不是在逻辑方面),并且它与特定测试用例相关……要么在某处存在错误。这可能是第一个,因为我有根据的猜测是他们在后端使用经过验证的编译器。
由于我们看不到运行时错误、测试设置和测试结果,因此我们无法进一步挖掘。
现在我们来谈谈风格。
我的第一个工作解决方案如下:
#include <iostream>
using namespace std;
int main() {
int T; // number of tests
cin >> T;
for (int i = 0; i < T; i++) {
int N; // number of logicians
string logiciansWill; // "binary" string, should contain '0's and '1's; other chacters are treated as "IDK"
cin >> N >> logiciansWill;
bool foundNo = false;
for (int j = 0; j < N; j++){
// we're assuming logiciansWill[j] can only be '0' or '1'
bool logicianWantsBeer = logiciansWill[j] == '1';
if (foundNo) {
cout << "NO" << endl;
} else if (logicianWantsBeer) {
cout << ((j == N-1) ? "YES" : "IDK") << endl;
} else {
foundNo = true;
cout << "NO" << endl;
}
}
}
}
请注意,我使用了具有更好思想名称的变量:
logiciansWill
传达出它包含了所有逻辑学家的意志logicianWantsBeer
表示该变量告诉您特定逻辑学家是否想要啤酒。它具有无可争议的 bool
优势,因此编写 if
语句肯定更容易foundNo
表示我要么找到了一位能够回应 "NO"
的逻辑学家,要么没有。再次强调,最好将其设为 bool
,因为它只能是 true
或 false
另请注意,我将最后一个循环与其余循环之间的唯一区别合并到了
for
循环体内。这会导致代码少得多,而不会影响可读性。