PAT (Advanced Level) Practice 1034 Head of a Gang DFS遍历图

一、概述

找到每个帮派的头目。

最大的坑在于,通话记录有一千条,说明最多可以有两千个人,邻接矩阵开小了会段错误。

我测出来了测试点3,4,5的N都是1k,但是只有测试点3是超过1k人的。

我遇到的段错误除了爆栈就是数组不够大,以后遇到这种错误多往这上面想。

二、分析

首先注意输入格式:名字 名字 数字,第一件要做的就是给每个人编号,因为不能用名字作为邻接数组的序号。

使用map实现这一点,以人名做键,序号作为键值,那么就遇到了一个问题:重复的人名怎么办。

使用map.find()==map.end()来解决。find函数用于返回键对应的迭代器,如果不存在键,返回end。那么就可以用这个来判断是否已经给这个人编号了。

第二个要注意的是通话时间。

我开始直接把通话时间作为权值放在邻接矩阵中。将整个关系网作为无向图看待。但是之后发现了一个问题:

无论你是DFS还是BFS,都无法走遍所有的边,那么就一定会有有通话时间被遗漏。因此不能这样做。

要另开一个数组储存所有人的通话时间,邻接矩阵只是单纯记录连接关系。

接下来就是再开一个DFS必要的,其实BFS也必要的已访问数组了。

总而言之,整个算法要维护三个数组,即邻接矩阵,通话时长,已访问。

如下:

int N,K;
scanf("%d %d",&N,&K);
for(int i=0;i<N;i++)
{
	cin>>name1;
	cin>>name2;
	scanf("%d",&length);
	if(m.find(name1)==m.end())
	{
		m[name1]=people;
		people++;	
	}
	if(m.find(name2)==m.end())
	{
		m[name2]=people;
		people++;
	}
	fee[m[name1]]+=length;
	fee[m[name2]]+=length;
	call[m[name1]][m[name2]]=1;
	call[m[name2]][m[name1]]=1;
}

因为这不是一个连通图,所以DFS要使用多次,遍历即可。

for(int j=0;j<people;j++)
	{
		DFS(j);
		if(num<=2||timesum<=K*2)
		{
			timesum=0;
			num=0;
			head=0;
			timemax=0;
			continue;
		}
		else
		{
			map<string,int>::iterator it;
			for(it=m.begin();it!=m.end();it++)
			{
				if(it->second==head)
				{
					n[it->first]=num;
					break;
				}
			}
			timesum=0;
			bangnum++;
			num=0;
			head=0;
			timemax=0;
		}	
	}

因为我不喜欢在DFS中使用太多变量,那样会很晕,于是我加入了一大堆全局变量,并且在一次DFS之后将他们全部初始化。虽然有点麻烦,但是十分清晰易懂。一个小坑就是阈值K,因为我是把打电话和接电话的时间看成一个了,那么阈值应该乘二。否则样例2就过不去。对于所有头目,我们还需要根据值找键,因为值全是不等的,直接遍历寻找即可。找到后再另开一个map保存。

DFS函数如下:

void DFS(int member) 
{
	vis[member]=1;
	num++; 
	timesum+=fee[member];
	if(fee[member]>timemax)
	{
		head=member;
		timemax=fee[member];
	}
	for(int i=0;i<people;i++)
	{
		if(vis[i]==0&&call[member][i]!=0)
			DFS(i);
	}
}

与普通树的DFS差不多,但是普通树不存在访问相同的节点,对于图就要多一个已访问数组了。在DFS时,先把vis置为1,然后更新成员数量和总通话时间,同时判断是否更新头目。接下来遍历邻接矩阵的相同行即可。

最后按格式输出。

三、总结

需要的变量和维护的数组有点多,因为条件较多。注意理清逻辑。

PS:代码如下:

#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
//邻接矩阵版
//DFS
int call[2010][2010]={0}; 
int bangnum=0;
int fee[2010]={0};
int vis[2010]={0};
int people=0;
map<string,int> m,n;
int num=0;//成员总人数 
int timemax=0;//最长时间 
int timesum=0;
int head=-1; //头目序号 
void DFS(int member) 
{
	vis[member]=1;
	num++; 
	timesum+=fee[member];
	if(fee[member]>timemax)
	{
		head=member;
		timemax=fee[member];
	}
	for(int i=0;i<people;i++)
	{
		if(vis[i]==0&&call[member][i]!=0)
			DFS(i);
	}
}
string name1,name2;
int length;
int main()
{
	int N,K;
	scanf("%d %d",&N,&K);
	//测试点345都是1000
	for(int i=0;i<N;i++)
	{
		cin>>name1;
		cin>>name2;
		scanf("%d",&length);
		if(m.find(name1)==m.end())
		{
			m[name1]=people;
			people++;	
		}
		if(m.find(name2)==m.end())
		{
			m[name2]=people;
			people++;
		}
		fee[m[name1]]+=length;
		fee[m[name2]]+=length;
		call[m[name1]][m[name2]]=1;
		call[m[name2]][m[name1]]=1;
	}
	
	for(int j=0;j<people;j++)
	{
		DFS(j);
		if(num<=2||timesum<=K*2)
		{
			timesum=0;
			num=0;
			head=0;
			timemax=0;
			continue;
		}
		else
		{
			map<string,int>::iterator it;
			for(it=m.begin();it!=m.end();it++)
			{
				if(it->second==head)
				{
					n[it->first]=num;
					break;
				}
			}
			timesum=0;
			bangnum++;
			num=0;
			head=0;
			timemax=0;
		}	
	}
	cout<<bangnum<<'\n';
	if(bangnum!=0)
	{
		map<string,int>::iterator it1;
		for(it1=n.begin();it1!=n.end();it1++)
			cout<<it1->first<<' '<<it1->second<<'\n';
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值