一、概述
找到每个帮派的头目。
最大的坑在于,通话记录有一千条,说明最多可以有两千个人,邻接矩阵开小了会段错误。
我测出来了测试点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';
}
}