「1158」Telefraud Detection

Telefraud(电信诈骗) remains a common and persistent problem in our society. In some cases, unsuspecting victims lose their entire life savings. To stop this crime, you are supposed to write a program to detect those suspects from a huge amount of phone call records.

A person must be detected as a suspect if he/she makes more than K short phone calls to different people everyday, but no more than 20% of these people would call back. And more, if two suspects are calling each other, we say they might belong to the same gang. A makes a short phone call to B means that the total duration of the calls from A to B is no more than 5 minutes.

Input Specification:

Each input file contains one test case. For each case, the first line gives 3 positive integers  , the threshold(阈值) of the amount of short phone calls),  , the number of different phone numbers), and  , the number of phone call records). Then M lines of one day’s records are given, each in the format:

caller receiver duration

where caller and receiver are numbered from 1 to N, and duration is no more than 1440 minutes in a day.

Output Specification:

Print in each line all the detected suspects in a gang, in ascending order of their numbers. The gangs are printed in ascending order of their first members. The numbers in a line must be separated by exactly 1 space, and there must be no extra space at the beginning or the end of the line.

If no one is detected, output None instead.

Sample Input 1:

5 15 31
1 4 2
1 5 2
1 5 4
1 7 5
1 8 3
1 9 1
1 6 5
1 15 2
1 15 5
3 2 2
3 5 15
3 13 1
3 12 1
3 14 1
3 10 2
3 11 5
5 2 1
5 3 10
5 1 1
5 7 2
5 6 1
5 13 4
5 15 1
11 10 5
12 14 1
6 1 1
6 9 2
6 10 5
6 11 2
6 12 1
6 13 1

Sample Output 1:

3 5
6

Note: In sample 1, although 1 had 9 records, but there were 7 distinct receivers, among which 5 and 15 both had conversations lasted more than 5 minutes in total. Hence 1 had made 5 short phone calls and didn’t exceed the threshold 5, and therefore is not a suspect.

Sample Input 2:

5 7 8
1 2 1
1 3 1
1 4 1
1 5 1
1 6 1
1 7 1
2 1 1
3 1 1

Sample Output 2:

None

Ω

题目比较复杂,揉杂了很多考点,但只要把题目读懂,理清条件就还好。给出若干通电话记录,包括拨打者、接听者和通话时长,如果一个人给 个【不同】的人打了【短】通话(作为【拨打者】通话【总】时长≤ 5 min)电话,而且【这些人】中只有≤ 20%的人回拨,就认定这是一个电信诈骗嫌疑犯。另外如果两个嫌疑人之间【互通】电话,那么我们认为他们可能属于同一个团伙。最后输出所有嫌疑犯,一行一个团伙,按照升序输出。

需要注意的点都用【】标注出来了,可以看到只要有一个地方没理解透彻就翻车。注意到人数 不会超过1000,所以我打算用bitset来分别标记打出记录和接听记录:bitset<1000> call(n),rec(n)。由于需要记录短通话的次数,因此用一个二维数组存储单向拨打通话总时长。注意到call和rec的信息其实是等价的,因此我们用call来标记短通话。当两个人之间存在通话记录就在拨打者的call里进行标记,如果单向通话时长超过5min,就取消标记。rec只要有通话记录都标记。

那么 拨打短通话的不同人数就是call[i]中1的数量call[i].count(),而回拨的人数我们只考虑那些有接听 的短通话的人群,即call[i][j]&&rec[i][j]。最终我们将这部分人数 (需要保证整型不会溢出)再和call[i].count()进行比较,将嫌疑人存入vector<int> sus。最后再对sus进行DFS或BFS或并查集来求取连通分图,我这里用了DFS。


🐎

#include <iostream>
#include <vector>
#include <bitset>
#include <algorithm>

using namespace std;
vector<vector<int>> edge;
vector<bool> flag;

void dfs(int n, vector<int> &gang)
{
    flag[n] = true, gang.push_back(n);
    for (auto &k: edge[n])
    {
        if (flag[k]) continue;
        dfs(k, gang);
    }
}

int main()
{
    int k, n, m, c, r, d, cnt = 0;
    cin >> k >> n >> m;
    vector<bitset<1000>> call(n), rec(n);
    vector<vector<int>> dur(n, vector(n, 0));
    for (int i = 0; i < m; ++i)
    {
        cin >> c >> r >> d;
        call[c - 1][r - 1] = (dur[c - 1][r - 1] += d) <= 5;
        rec[r - 1][c - 1] = true;
    }
    vector<int> sus, gang;
    for (int i = 0; i < n; ++i, cnt = 0)
    {
        for (int j = 0; j < n; ++j) cnt += (call[i][j] && rec[i][j]);
        if (call[i].count() > k && 5 * cnt <= call[i].count())
            sus.push_back(i);
    }
    if (sus.empty()) printf("None");
    else
    {
        edge.resize(sus.size()), flag.resize(sus.size(), false);
        for (int i = 0; i < sus.size(); ++i)
            for (int j = i + 1; j < sus.size(); ++j)
                if (rec[sus[i]][sus[j]] && rec[sus[j]][sus[i]])
                    edge[i].push_back(j), edge[j].push_back(i);
        for (int i = 0; i < sus.size(); ++i, gang.clear())
        {
            if (flag[i]) continue;
            dfs(i, gang);
            sort(gang.begin(), gang.end(), [&sus](int a, int b) { return sus[a] < sus[b]; });
            for (int j = 0; j < gang.size(); ++j)
                printf("%d%s", sus[gang[j]] + 1, j == gang.size() - 1 ? "\n" : " ");
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值