Codeforces 156b Suspects

10 篇文章 0 订阅
3 篇文章 0 订阅
  • 题意: 询问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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值