PAT 甲级 1158 Telefraud Detection

本文介绍了一种用于检测电信诈骗的算法,通过对大量电话记录的分析,识别出可能的诈骗嫌疑人及团伙。算法考虑了每日短电话数量、回调率及嫌疑人之间的相互呼叫关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 (≤10​3​​, the number of different phone numbers), and M (≤10​5​​, 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 1had 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;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值