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

总结:并查集+模拟

相关推荐
求梦8201 分钟前
【力扣hot100题】合并两个有序链表(22)
算法·leetcode·链表
dcmfxvr14 分钟前
adwawd
算法
啊阿狸不会拉杆23 分钟前
《数字信号处理 》第 7 章-无限长单位冲激响应 (IIR) 数字滤波器设计方法
数据结构·算法·信号处理·数字信号处理·dsp
IT_Octopus27 分钟前
力扣热题100 20. 有效的括号
算法·leetcode
木井巳29 分钟前
【递归算法】求根节点到叶节点数字之和
java·算法·leetcode·深度优先
想进个大厂33 分钟前
代码随想录day29 贪心03
算法·leetcode·职场和发展
We་ct1 小时前
LeetCode 15. 三数之和:排序+双指针解法全解析
前端·算法·leetcode·typescript
挽天java1 小时前
数据结构习题--寻找旋转排序数组中的最小值
数据结构·算法·排序算法
你怎么知道我是队长1 小时前
C语言---排序算法4---希尔排序法
c语言·算法·排序算法
iAkuya1 小时前
(leetcode)力扣100 54实现Trie树
算法·leetcode·c#