PAT 1034 Head of a Gang

发布于:2025-08-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

在这里插入图片描述
在这里插入图片描述
题目的大意是有不同的人通话,当人数超过2个,并且通话时间大于K,那么我们就
称它为gang,在每一个gang中某个人的通话时间最多,就把最多的那个人称为head
现在让我们找有多少个gang,每一个gang中的head是谁,这个gang里面有多少人。
很明显的是,这需要建图,但都是人名,字符串,建图的时候需要把字符串转换成数字,方便建图.

int tobecomeid(string name)
{
	if(nametoid.count(name))
    {
    	return nametoid[name];
	}
	nametoid[name]=cnt;
	idtoname[cnt]=name;
	cnt++;
	return nametoid[name];
} 

边权也要注意,需要把两个人每次的通话时间都加起来,

The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. 

采用邻接矩阵建图,因为题目上说通话记录最多有1000,那么最坏的情况就是每次通话的两个人都不同,那么有2000人,建图是【2000】【2000】,内存大小是可以接受的。
因此建图已经明确了:


    cin>>N>>K;
	for(int i=0;i<N;i++)
    {
      string name1;
	  string name2;
	  int time;
	  cin>>name1>>name2>>time; 
	  int id1=tobecomeid(name1);
	  int id2=tobecomeid(name2);
	  a[id1][id2]+=time;
	  a[id2][id1]+=time;
	  weight[id1]+=time;
	  weight[id2]+=time;
	}

而我们只需要用dfs在图中找连通分量,只需要保证这个连通分量中的成员个数>2,
总的通话时间>K,即是符合条件的gang,同时我们在dfs找连通分量的过程中找最大的weight作为head,即可满足题意。

void dfs(int x,int &totalweight,int &member,int &head)
{
	vis[x]=true;
	member++;
	totalweight+=weight[x];
	if(weight[head]<weight[x])
	{
		head=x;
	}
	for(int i=0;i<cnt;i++)
	{
		if(vis[i]==0&&a[x][i]!=0)
		{
			dfs(i,totalweight,member,head);
		}
	}
    
}
    for(int i=0;i<cnt;i++)
	{
		if(vis[i]==0)
		{
			int head=i;
			int totalweight=0;
			int member=0;
			dfs(i,totalweight,member,head);
			//这样就得到一个连通分量我们来判断它是不是
			//符合条件
		    if(totalweight/2>K&&member>2)
		    {
		    	
				ans[idtoname[head]]=member;
			}
			 
		}
	} 

注意要采用值传递,因为在dfs遍历一次后我们要判断该连通分量是否符合题意

            if(totalweight/2>K&&member>2)
		    {
		    	//说明符合条件
				//但不代表可以直接输出
				ans[idtoname[head]]=member;
			}

采用上述的方法
如果符合条件那么我们就需要保存这个gang的head,和它的总的成员数member,
但是我们不能直接输出,需要把数字再重新转化成字符串(名字)(在转数字的函数中可以同时做这件事)

int tobecomeid(string name)
{
	if(nametoid.count(name))
    {
    	return nametoid[name];
	}
	nametoid[name]=cnt;
	idtoname[cnt]=name;
	cnt++;
	return nametoid[name];
} 

题目上说要按照字典顺序输出,因此我们再用一个map来保存这些字符串和它对应的成员数
最后按照题意输出即可。

   map<string,int> ans; 
   cout<<ans.size()<<endl;
	for(auto it: ans)
	{
		cout<<it.first<<" "<<it.second<<endl;
	}

完整代码如下:

#include <iostream>
#include <limits.h>
#include <cstring>
#include <queue>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
int N;
int K; 
int a[2005][2005];
int weight[2005];
unordered_map<string,int> nametoid;
unordered_map<int,string> idtoname; 
int cnt;
bool vis[2005];
int tobecomeid(string name)
{
	if(nametoid.count(name))
    {
    	return nametoid[name];
	}
	nametoid[name]=cnt;
	idtoname[cnt]=name;
	cnt++;
	return nametoid[name];
} 
void dfs(int x,int &totalweight,int &member,int &head)
{
	vis[x]=true;
	member++;
	totalweight+=weight[x];
	if(weight[head]<weight[x])
	{
		head=x;
	}
	for(int i=0;i<cnt;i++)
	{
		if(vis[i]==0&&a[x][i]!=0)
		{
			dfs(i,totalweight,member,head);
		}
	}
    
}
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>N>>K;
	for(int i=0;i<N;i++)
    {
      string name1;
	  string name2;
	  int time;
	  cin>>name1>>name2>>time; 
	  int id1=tobecomeid(name1);
	  int id2=tobecomeid(name2);
	  a[id1][id2]+=time;
	  a[id2][id1]+=time;
	  weight[id1]+=time;
	  weight[id2]+=time;
	}
	//图已经建好
	map<string,int> ans; 
	for(int i=0;i<cnt;i++)
	{
		if(vis[i]==0)
		{
			int head=i;
			int totalweight=0;
			int member=0;
			dfs(i,totalweight,member,head);
			//这样就得到一个连通分量我们来判断它是不是
			//符合条
		    if(totalweight/2>K&&member>2)
		    {
		    	//说明符合条件
				//但不代表可以直接输出
				ans[idtoname[head]]=member;
			}
			 
		}
	} 
	cout<<ans.size()<<endl;
	for(auto it: ans)
	{
		cout<<it.first<<" "<<it.second<<endl;
	}
	
    
    
	return 0;
 } 

虽然题目的本质只是一个建图+dfs找连通分量,但过程还是需要考虑很多的条件,较复杂。


网站公告

今日签到

点亮在社区的每一天
去签到