一、原题
犯罪团伙(gang.cpp)
题目描述
警察抓到了n个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。
有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从1至n。
输入
第1行:n(<=500,罪犯数量),m(<50000,关系数量)
以下m行:每行两个数:i 和j,中间一个空格隔开,表示罪犯i和罪犯j相互认识。
输出
第1行:一个整数,犯罪团伙的数量。
样例输入
11 8
1 2
4 3
5 4
1 3
5 6
7 10
5 10
8 9
样例输出
3
概念图
二、分析
这道题首先我一看,就需要用到邻接表,所以,我们先定义两个临时变量来存储能够相互连通的数。
bool a[502][502];//定义bool类型的邻接表
for(int i=1;i<=m;i++){//建立邻接表
int x,y;//临时变量
cin>>x>>y;//读入
a[x][y]=a[y][x]=1;//标记以建立邻接表
}
然后我们就要就要搜索了,首先,我们把搜索函数的函数搭建好,这个搜索函数主要是删点,顺便把用过的点记录一下,好为没有与其它点连通的点计数,为单独的犯罪团伙。
void dfs(int x){//删除点的函数
for(int i=1;i<=n;i++){
if(a[x][i]){//如果x与i联通
a[x][i]=a[i][x]=0;//在邻接表中删掉两个点的联通
p[x]=p[i]=1;//记录已被记录的点
dfs(i);//继续搜索
}
}
}
然后,用for循环,把一个一个的调用函数一下,同上,记录点已经被使用过。
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]){
p[i]=p[j]=1;//记录点已被使用过
dfs(i);//搜索以删点
ans++;//答案+1
}
最后,我们愉快的把那些不与任何点连通的点单独算作一个犯罪团伙就行啦。
for(int i=1;i<=n;i++)
if(!p[i])//不与任何点连通的点
ans++;//答案+1
输出答案,这道题就是那么的简单。完整的代码如下:)
三、源代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<time.h>
#include<algorithm>
#include<queue>
using namespace std;
bool a[502][502],p[502];
int b=1,t,n,f,ans,m;
void fre(){//文件的读入输出
freopen("gang.in","r",stdin);
freopen("gang.out","w",stdout);
}
void dfs(int x){//删除点的函数
for(int i=1;i<=n;i++){
if(a[x][i]){//如果x与i联通
a[x][i]=a[i][x]=0;//在邻接表中删掉两个点的联通
p[x]=p[i]=1;//记录已被记录的点
dfs(i);//继续搜索
}
}
}
int main()
{
//fre();//文件的输入输出
cin>>n>>m;
for(int i=1;i<=m;i++){//建立邻接表
int x,y;//临时变量
cin>>x>>y;//读入
a[x][y]=a[y][x]=1;//标记以建立邻接表
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]){
p[i]=p[j]=1;//记录点已被使用过
dfs(i);//搜索以删点
ans++;//答案+1
}
for(int i=1;i<=n;i++)
if(!p[i])//不与任何点连通的点
ans++;//答案+1
cout<<ans;
}