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);

总结:并查集+模拟

相关推荐
吃好睡好便好6 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
仰泳之鹅6 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
x_yeyue9 小时前
三角形数
笔记·算法·数论·组合数学
念何架构之路10 小时前
Go语言加密算法
数据结构·算法·哈希算法
AI科技星10 小时前
《数学公理体系·第三部·数术几何》(2026 年版)
c语言·开发语言·线性代数·算法·矩阵·量子计算·agi
失去的青春---夕阳下的奔跑10 小时前
560. 和为 K 的子数组
数据结构·算法·leetcode
黎阳之光10 小时前
黎阳之光:以视频孪生重构智慧医院信息化,打造高标项目核心竞争力
大数据·人工智能·物联网·算法·数字孪生
丷丩11 小时前
三级缓存下MVT地图瓦片服务性能优化策略
算法·缓存·性能优化·gis·geoai-up
m0_6294947311 小时前
LeetCode 热题 100-----25.回文链表
数据结构·算法·leetcode·链表
ʚ希希ɞ ྀ12 小时前
单词拆分----dp
算法