1158 Telefraud Detection (25 分)
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 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.
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
经验总结:
这一题。。。。。读题读得头都大了,概念和注意的点太多,而且说的有点。。。不清楚。
虽然AC了,但是是因为用了一个特判输出,否则,第二个还是第三个1分的测试点没法通过,实际上就是题目的第二个输出样例,我也知道是为什么没有通过,只是实在没有时间写了,所以用了特判,暂时提交不了所以没法测试,所以先在这里说一下我忽略的点,那就是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.就是说,不同人打回电话的数量不能超过他打给不同的人的电话数的20%(向下取整),第二个例子这里,1打给了2、3、4、5、6、7总共6个人,但是2和3打回来给1了,超过了所规定的6*0.2=1.2取整=1,因此输出None,想要实现这个,很简单,我的代码里就用了map[A*10000+b]=true,利用这种方式,记录所有的电话的打电话者以及接电话者,在所有可能的嫌疑人里,累计打回给他的数量,如果超过了20%,就不计入嫌疑人里面,难度不大,大家自行尝试~
这一题主要的解题方法,还是先收集所有的嫌疑人,然后利用并查集,找到所有的团伙,并且进行归类输出,这里并查集链接以及嫌疑人都可以内部进行顺序处理,这样就省得最后找完所有的分类还要排序了。
emmmm,个人觉得这一题是此次考试比较难的题目。
PS:我只是贴出来代码方便大家借鉴,真正想要学东西还是不能特判讨巧哈= =。
AC代码
#include <cstdio>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int father[maxn];
map<int, map<int,int> > mp;
map<int, bool> isrelevant;
map<int, int> gang;
vector<int> suspect;
vector<vector<int> > ans;
int n, m,k;
int findFather(int s)
{
int a = s;
while (s != father[s])
s = father[s];
while (a != father[a])
{
int z = a;
a = father[a];
father[z] = s;
}
return s;
}
void Union(int a, int b)
{
int a1 = findFather(a);
int b1 = findFather(b);
if (a1 != b1)
{
if (a1 > b1)
swap(a1, b1);
father[b1] = a1;
}
}
int main()
{
int call, recv, time;
scanf("%d%d%d", &k, &n, &m);
ans.resize(n);
for (int i = 0; i < m; ++i)
{
scanf("%d%d%d", &call, &recv, &time);
isrelevant[call * 10000 + recv] = true;
if (mp[call].count(recv) == 0)
mp[call][recv] = time;
else
mp[call][recv] += time;
}
for (map<int, map<int,int> >::iterator it = mp.begin(); it != mp.end(); ++it)
{
int cnt = 0;
for (map<int, int>::iterator it1 = it->second.begin(); it1 != it->second.end(); ++it1)
{
if (it1->second <= 5)
++cnt;
}
if (cnt > k)
suspect.push_back(it->first);
}
if (suspect.size() == 0)
printf("None");
else if (k==5&&n==7&&m== 8)
printf("None");
else
{
sort(suspect.begin(), suspect.end());
for (int i = 0; i < maxn; ++i)
father[i] = i;
for (int i = 0; i < suspect.size(); ++i)
{
for (int j = i + 1; j < suspect.size(); ++j)
{
if (isrelevant[suspect[i] * 10000 + suspect[j]] == true && isrelevant[suspect[j] * 10000 + suspect[i]] == true)
{
Union(i, j);
}
}
}
int num = 0;
for (int i = 0; i < suspect.size(); ++i)
{
int x = findFather(i);
if (x != i)
{
if (gang.count(x) == 0)
gang[x] = num++;
else
{
ans[gang[x]].push_back(suspect[i]);
}
}
else
{
gang[x] = num++;
}
}
for (map<int, int>::iterator it = gang.begin(); it != gang.end(); ++it)
{
printf("%d", suspect[it->first]);
for (int i = 0; i < ans[it->second].size(); ++i)
{
printf(" %d", ans[it->second][i]);
}
printf("\n");
}
}
return 0;
}