学习C++从娃娃抓起!记录下USACO(美国信息学奥赛)备考青铜组别比赛学习过程中的题目,记录每一个瞬间。
附上汇总贴:USACO历年青铜组真题解析 | 汇总-CSDN博客
【题目描述】
Elsie 有一个程序,接受一个 N(1≤N≤100) 个变量的数组 b[0],⋯,b[N−1] 作为输入,其中每个变量等于 0 或 1,并且返回对输入数组应用一系列 if / else if / else 语句的结果。每个语句检查至多一个输入变量的值,并返回 0 或 1。这类程序的一个例子是:
if (b[1] == 1) return 1;
else if (b[0] == 0) return 0;
else return 1;
例如,如果上方程序的输入是 "10"(即 b[0]=1 及 b[1]=0),那么输出应当为 1。
Elsie 告诉了 Bessie 对于 M(1≤M≤100) 个不同输入的正确输出。Bessie 现在正试图对 Elsie 的程序进行逆向工程。不幸的是,Elsie 可能说了谎;可能不存在上述形式的程序行为与 Elsie 所说的均一致。
对于 T(1≤T≤10) 个子测试用例中的每一个,判断 Elsie 是否一定在说谎。
【输入】
输入的第一行包含 T,为子测试用例的数量。
每一个子测试用例的第一行包含两个整数 N 和 M,以下 M 行,每行包含一个由 N 个 0 或 1 组成的字符串,表示一个输入(即 b[0]⋯b[N−1] 的值),以及另一个字符(0 或 1)表示输出。相邻的子测试用例之间用空行分隔。
【输出】
对于每一个子测试用例,输出一行,包含 OK 或 LIE,分别表示 Elsie 可能没有说谎或是一定在说谎。
【输入样例】
4
1 3
0 0
0 0
1 1
2 4
00 0
01 1
10 1
11 1
1 2
0 1
0 0
2 4
00 0
01 1
10 1
11 0
【输出样例】
OK
OK
LIE
LIE
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int t;
bool res[105], del[105]; // 定义res数组存放每行数据的输出,del数组存放改行后续是否不再遍历的标志位
string s[105];
int n, m;
int main()
{
cin >> t; // 输入t
while (t--) { // 遍历t组数据
cin >> n >> m; // 输入n和m
for (int i=1; i<=m; i++) { // 输入m行输入数据
cin >> s[i] >> res[i]; // 每行数据包含一个字符串s,和对应结果res
}
memset(del, false, sizeof(del)); // 每次检查冲突前先初始化del数组
for (int k=1; k<=n; k++) { // 第一轮遍历到n列,可以确定n列是否有冲突,那么n-1列就需要第2轮遍历,所以最多需要n轮(如判断程序时先比较b[1],再比较b[0],则需要第1位判断之后,再进行第0位的判断)
for (int i=0; i<n; i++) { // 遍历s字符串的n个字符,即逐列比较
bool conflict0 = false, conflict1 = false; // 定义变量表示输入0是否冲突,输入1是否冲突
int last0 = -1, last1 = -1; // 记录最近一次输入为0时的输出,以及最近一次输入为1的输出
for (int j=1; j<=m; j++) {
if(del[j]) continue; // 下一轮判断,可以剔除那些已经删除的行(对于n轮判断也起到过滤作用)
bool num = (s[j][i]=='1'); // 轻巧,定义num,讲s[j][i]变向地转为数字
if (num) { // 如果输入为1
if (last1==-1) { // 如果没有比较过
last1 = res[j]; // 则输入为1对应的输出为res[j]
} else if (last1 != res[j]) { // 如果比较过,且此次输入对应的输出不等于最近一次比较的输出(即说明冲突)
conflict1 = true; // 标记1冲突了
}
} else { // 如果输入为0
if (last0==-1) { // 如果没有比较过
last0 = res[j]; // 则输入为0对应的输出为res[j]
} else if (last0 != res[j]) { // 如果比较过,且此次输入对应的输出不等于最近一次比较的输出(即说明冲突)
conflict0 = true; // 标记0冲突了
}
}
}
for (int j=1; j<=m; j++) { // 遍历m行
if (s[j][i]=='0' && !conflict0) { //对于输入为0且不冲突的行
del[j] = true; // 标记del[j]为true,下次比较直接忽略改行(相当于删除该行)
}
if (s[j][i]=='1' && !conflict1) { //对于输入为1且不冲突的行
del[j] = true; // 标记del[j]为true,下次比较直接忽略改行(相当于删除该行)
}
}
}
}
int mark = 0; // 定义mark标识位,用来确定最后输出,初始为0
for (int i=1; i<=m; i++) { // 遍历m行
if (del[i]==false) { // 如果有任一一行为false,则说明这行的输入对应的输出有冲突(即为假)
mark = 1; // 修改mark为1
break; // 退出循环
}
}
if (mark==0) cout << "OK" << endl; // 如果mark不变,仍为0,说明都是不冲突的(即为真)
else cout << "LIE" << endl; // 否则输出LIE
}
return 0;
}
【运行结果】
4
1 3
0 0
0 0
1 1
OK
2 4
00 0
01 1
10 1
11 1
OK
1 2
0 1
0 0
LIE
2 4
00 0
01 1
10 1
11 0
LIE