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.
Each input file contains one test case. For each case, the first line gives 3 positive integers K (≤500, the threshold(阈值) of the amount of short phone calls), N (≤103, the number of different phone numbers), and M (≤105, 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.
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.
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
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.
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
None
题目大意:编写一个程序,从大量的通话记录中检测出电信诈骗嫌疑人。如果一个人每天给不同的人打超过K个短电话,但这些人中回电的比例不超过20%,那他可能是嫌疑人。而且,如果两个嫌疑人互相打电话,我们认为他们可能属于同一个团伙。A给B打短电话是指A到B的通话总时长不超过5分钟。给三个正整数:短电话数量的阈值K,不同电话号码的数量N,通话记录数量M。接下来M行给出一天的通话记录,格式为呼叫者caller、接收者receiver、时长duration。输出格式:在每一行输出一个团伙中所有检测到的嫌疑人,按数字升序排列。这些帮派按第一个成员的升序排列。一行中的数字必须使用1个空格分隔,并且行首或行尾不得有多余空格。
分析:p为并查集的父集,sc中存储短通话的人数,rec中存储短通话收到回电的人数,mark用来标记是否输出过,record记录两个人的通话总时长,su中保存嫌疑人的编号。我们先记录下来两人之间的通话总时间,以此来统计短通话以及回电的次数,进而判断出某个人是不是嫌疑人。如果没有嫌疑人,则输出None。因为要按照帮派输出,所以我们用并查集把互相通过电话的嫌疑人设置到同一个集合内,然后就可以输出答案了~
- #include
- #include
- using namespace std;
- int k, n, m, c, r, d, p[1001], sc[1001], rec[1001], mark[1001], record[1001][1001];
- vector<int> su;
- int Find(int a) {
- if (p[a] != a) return p[a] = Find(p[a]);
- return a;
- }
- void add(int a, int b) {
- int f1 = Find(a), f2 = Find(b);
- if (f1 < f2) p[f2] = f1;
- else p[f1] = f2;
- }
- int main() {
- for (int i = 1; i <= 1000; i++) p[i] = i;
- cin >> k >> n >> m;
- for (int i = 0; i < m; i++) {
- cin >> c >> r >> d;
- record[c][r] += d;
- }
- for (int i = 1; i <= n; i++) {
- for (int j = 1; j <= n; j++) {
- if (record[i][j] && record[i][j] <= 5) {
- sc[i]++;
- if (record[j][i]) rec[i]++;
- }
- }
- if (sc[i] > k && rec[i] * 5 <= sc[i]) su.push_back(i);
- }
- if (su.empty()) {
- cout << "None";
- return 0;
- }
- for (int i = 0; i < su.size(); i++) {
- for (int j = i + 1; j < su.size(); j++) {
- if (record[su[i]][su[j]] && record[su[j]][su[i]]) add(su[i], su[j]);
- }
- }
- for (int i = 0; i < su.size(); i++) {
- if (mark[su[i]]) continue;
- cout << su[i];
- for (int j = i + 1; j < su.size(); j++) {
- if (Find(su[i]) == Find(su[j])) {
- cout << ' ' << su[j];
- mark[su[j]] = 1;
- }
- }
- cout << '\n';
- }
- return 0;
- }