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" : " ");
}
}
}