PAT 1158 Telefraud Detection


这一题的大意是说,给出M个通话记录,让我们找嫌疑人,一个人如果超过K次短通话记录给不同的人每天,但是不超过20%的人打回来,那么它就是一个嫌疑人,而且如果两个怀疑的人互相打电话我们认为他们可能属于团伙

短通话是指总时长不超过5分钟.最后需要把属于一个团伙按照编号从小到大的顺序输出。不同的团伙也按照从编号从小到大的顺序输出。

题目中的数据范围比较小,模拟这个过程并不难:

cpp 复制代码
#include<bits/stdc++.h>
#include<iostream> 
using namespace std;
//从大量的通话记录中探测怀疑的人
//一个人必须被探测作为一个怀疑者如果他做出了
//超过K次短通话记录给不同的人每天
//但是不超过20%的人打回来
//而且如果两个怀疑的人互相打电话我们认为他们可能属于团伙
//短通话是指总时长不超过K分钟
int K;
int N;
int M; 
int f[1005];
int n[1005][1005];
int cnt[1005];
int callback[1005];
int find(int x)
{
	if(f[x]!=x)
	{
		return find(f[x]);
	}
	else
	{
		return x;
	}
	
 } 
bool flag[1005];
int main()
{
    cin>>K>>N>>M;
    for(int i=0;i<1005;i++)
    {
    	f[i]=i;
	}
   for(int i=0;i<M;i++)
   {
   	int caller;
   	int receiver;
   	int duration;
   	cin>>caller>>receiver>>duration;
   	n[caller][receiver]+=duration;	
   }
   for(int i=1;i<=N;i++)
   {
   	 for(int j=1;j<=N;j++)
	 {
	 	if(i!=j)
	 	{
	 		if(n[i][j]<=5&&n[i][j]>0)
	 		{
	 		   //不能超过阈值才算做符合条件的通话
			   cnt[i]++;	
			}
	 	   if(n[i][j]>0&&n[i][j]<=K&&n[j][i]>0)
		   {
		   	callback[i]++;
		   }	
		}
	       		
	 }	
   }
   //cout<<cnt[1]<<endl;
   vector<int> crime;
   for(int i=1;i<=N;i++)
   {
   	  if(cnt[i]>K)
   	  {
   	      int x=cnt[i];
   	      //cout<<x<<" ";
		  if(callback[i]<=x*0.2)
		  {
		       	crime.push_back(i);
		  }	
	  }
   }
   if(crime.size()==0)
   {
   	cout<<"None"<<endl;
   	return 0;
   }
   for(int i=0;i<crime.size();i++)
   {
   	for(int j=i+1;j<crime.size();j++)
   	{
   		if(n[crime[i]][crime[j]]>0&&n[crime[j]][crime[i]]>0)
   		{
   		 int fa=find(crime[i]);
   	     int fb=find(crime[j]);
   	     if(fa==fb)
   	     {
   	        //说明在一个帮里面不用管	
		 }
		 else
		 {
		 
		 	f[fa]=fb;
		 }
		}
   	    
	}
   }
   vector<vector<int>> total(N);
   int t=0;
   //我们现在把同一个帮派的放到了一个并查集里面了 
   for(int i=0;i<crime.size();i++)
   {
   	  if(flag[crime[i]])
   	  {
   	  	continue;
	  }
	  cout<<crime[i];
	  for(int j=i+1;j<crime.size();j++)
	  {
	  	   if(find(crime[i])==find(crime[j]))
	  	   {
	  	        cout<<" "<<crime[j];
				  flag[crime[j]]=1;	
		   }
	  }
	  cout<<endl;
   }
    
   
    return 0;
}

注意嫌疑人是否是在同一个团伙中,用并查集来判断。

最后的按顺序输出对我来说不太轻松,我参考了柳神的输出方法

实际上可以用哈希表分组输出:

cpp 复制代码
map<int, vector<int>> groups;
for (int x : crime)
{
    int root = find(x);
    groups[root].push_back(x);
}
//组内排序
for (auto &g : groups)
{
    sort(g.second.begin(), g.second.end());
}
//组间排序
vector<vector<int>> ans;

for (auto &g : groups)
{
    ans.push_back(g.second);
}

sort(ans.begin(), ans.end(), [](const vector<int>& a, const vector<int>& b){
    return a[0] < b[0];
});

这种方法挺麻烦的,但好理解。

二维数组不同组间的排序还可以这样输出:

cpp 复制代码
vector<pair<int, vector<int>>> ans;
bool cmp(const vector<int>& a, const vector<int>& b)
{
    return a[0] < b[0];
}

sort(ans.begin(), ans.end(), cmp);

总结:并查集+模拟

相关推荐
embrace992 小时前
【C语言学习】预处理详解
java·c语言·开发语言·数据结构·c++·学习·算法
拼好饭和她皆失2 小时前
《二分答案算法精讲:从原理到实战(上篇)》
c++·算法
好风凭借力,送我上青云2 小时前
Pytorch经典卷积神经网络-----激活函数篇
人工智能·pytorch·深度学习·算法·矩阵·cnn
Tisfy2 小时前
LeetCode 3652.按策略买卖股票的最佳时机:滑动窗口
算法·leetcode·题解·滑动窗口
扫地的小何尚2 小时前
NVIDIA CUDA-Q QEC权威指南:实时解码、GPU解码器与AI推理增强
人工智能·深度学习·算法·llm·gpu·量子计算·nvidia
重生之我是Java开发战士2 小时前
【数据结构】优先级队列(堆)
java·数据结构·算法
菜鸟233号2 小时前
力扣216 组合总和III java实现
java·数据结构·算法·leetcode
大柏怎么被偷了2 小时前
【Linux】重定向与应用缓冲区
linux·服务器·算法
AuroraWanderll2 小时前
类和对象(三)-默认成员函数详解与运算符重载
c语言·开发语言·数据结构·c++·算法