- 题意: 询问n个嫌疑人,每个人有两种回答,+i和-i, +i表示第i个人是罪犯,-i表示第i个人不是罪犯,每个人能且只能回答一次,已知有m个人说的是实话,问第i个人说的是实话还是谎话,或者不能确定.
- 思路: 这个题其实重点就是根据有m个人说实话去判断谁是罪犯. 朴素的思路就是假设第i个人是罪犯,然后扫描所有人的回答,检测是否有m个人在说实话.但是这样复杂度是
O(n2)
. 接下来就是如果去优化这个思路.假设第i个人是罪犯,可以知道如果有m个人说第i个人是罪犯,说某人不是罪犯的总人数为t_n,说第i个人不是罪犯的人数是n,那么可以知道此时说真话的人数是m + t_n - n.所以如果预处理出m,t_n,n就可以以O(1)的复杂度计算第i个人是不是罪犯,而预处理m,t_n,n的复杂度是O(n),随意最终的时间复杂度是O(n).
- 一点小小的感想: 其实这道题是一个超级大水题,从题目编号就能看出来,但是还是将其写成题解是因为最开始思路不清晰,又用map又用set的,虽然把题目ac了,但是走了许多的弯路.代码也是修修补补的很丑. 一个算法的好坏的评价标准自己认为不能单单从时空复杂度来评判,代码的优美程度(简洁程度)也是很重要的,并且事实是往往很优美的算法也具有十分高效的效率. 所以在做一道题目的时候1.如果不能将这个算法从头到尾想清楚,就最好在多思考下,将细节已经算法的正确性想清楚后再开始写,不然很有可能做很多无用功,写了很多出来了,却发现从根本上就是错的.2.如果这个算法需要很多特判,比如用这个算法需要考虑非常多的特殊情况,需要将很多的情况分开处理,必须需要用很多的if语句,并且是不能一眼就看清楚流程的那种,也最好的停下来在多想一想,通常这种不会是最优解法,并且很有可能你会少考虑一些情况,进而整个算法也是错误的.最好的情况是这些复杂的不同的情况能够同一成一个问题解决.
- 总结:一个好的算法应该是简洁而优雅的
- 代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int yes[maxn], no[maxn], ans[maxn];
int A[maxn];
int cnt;
int tot_yes, tot_no;
int main()
{
int n, m;
cin >> n >> m;
for(int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
A[i] = x;
if(x > 0) {
tot_yes++;
yes[x]++;
} else {
tot_no++;
no[-x]++;
}
}
for(int i = 1; i <= n; i++) {
if(yes[i] + tot_no - no[i] == m) {
ans[i] = 1;
cnt++;
}
}
for(int i = 0; i < n; i++) {
int x = A[i];
if(x > 0) {
if(ans[x]) {
printf("%s\n", cnt > 1 ? "Not defined": "Truth");
} else {
printf("Lie\n");
}
} else {
x = -x;
if(ans[x]) {
printf("%s\n", cnt > 1 ? "Not defined": "Lie");
} else {
printf("Truth\n");
}
}
}
return 0;
}