目录
采用DFS遍历图
采用BFS遍历图
采用DFS遍历图
(1)邻接矩阵版
int n,G[maxn][maxn];
bool vis[maxn]={false};
void dfs(int u,int depth){vis[u]=true;for(int v=0;v<n;v++){if(vis[v]==false&&G[u][v]!=INF){dfs(v,depth+1);}}
}
void dfstrave(){for(int u=0;u<n;u++){if(vis[u]==false){dfs(u,1);}}
}
(2)邻接表版
vector<int> Adj[maxn];
int n;
bool vis[maxn]={false};
void dfs(int u,int depth){vis[u]=true;for(int i=0;i<Adj[u].size();i++){int v=Adj[u][i];if(vis[v]==false){dfs(v,depth+1);}}
}
void dfstrave(){for(int u=0;u<n;u++){if(vis[u]==false){dfs(u,1);}}
}
例题
给出若干人之间的通话长度(视为无向边),这些通话将他们分为若干组。每个组的总边权 设为该组内的所有通话的长度之和,而每个人的点权设为该人参与的通话长度之和。现在给定一个阈值K,且只要一个组的总边权超过K,并满足成员人数超过2,则该数组视为犯罪团伙,而该组内点权最大的人视为头目,要求输出“犯罪团伙”的个数,并按头目姓名字典序从小到大的顺序输出每个“犯罪团伙”的头目姓名和成员人数。
思路
(1)首先需要解决的问题是姓名与编号的对应关系。方法有二:一是使用map<string,int>直接建立字符串与整型的映射关系;二是使用字符串hash的方法将字符串转换为整型。编号与姓名的对应关系则可以直接用string数组进行定义,或者使用map<int,string>也是可以的。
(2)根据题目中的要求,需要获得每个人的点权,即与之相关的通话记录的时长之和,而这显然可以在读入时就进行处理(假设A与B的通话时长为T,那么A与B的点权分别增加T)。事实上,该步是在求与某个点相连的边的边权之和。
(3)进行图的遍历。使用DFS遍历每个连通块,目的是获取每个连通块的头目(即连通块内点权最大得结点)、成员个数、总边权。
(4)通过步骤3可以获得连通块的总边权totalValue。如果totalValue大于给定的阈值K,且成员人数大于2,则说明该连通块是一个团伙,将该团伙的信息存储下来。
注:可以定义map<string,int>来建立团队头目的姓名与成员人数的映射关系。由于map中元素自动按键从小到大排序,因此自动满足了题目要求的“姓名字典序从小到大输出“的规定。
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn=2010;
const int INF=1000000000;
map<int,string> intToString;
map<string,int> stringToInt;
map<string,int> Gang;
int G[maxn][maxn]={0},weight[maxn]={0};
int n,k,numPerson=0;
bool vis[maxn]={false};
void dfs(int nowVisit,int& head,int& numMember,int& totalValue){numMember++;vis[nowVisit]=true;if(weight[nowVisit]>weight[head]){head=nowVisit;}for(int i=0;i<numPerson;i++){if(G[nowVisit][i]>0){totalValue+=G[nowVisit][i];G[nowVisit][i]=G[i][nowVisit]=0;if(vis[i]==false){dfs(i,head,numMember,totalValue);}}}
}
void dfstrave(){for(int i=0;i<numPerson;i++){if(vis[i]==false){int head=i,numMember=0,totalValue=0;dfs(i,head,numMember,totalValue);if(numMember>2&&totalValue>k){Gang[intToString[head]]=numMember;}}}
}
int change(string str){if(stringToInt.find(str)!=stringToInt.end()){return stringToInt[str];}else{stringToInt[str]=numPerson;intToString[numPerson]=str;return numPerson++;}
}
int main(){int w;string str1,str2;cin>>n>>k;for(int i=0;i<n;i++){cin>>str1>>str2>>w;int id1=change(str1);int id2=change(str2);weight[id1]+=w;weight[id2]+=w;G[id1][id2]+=w;G[id2][id1]+=w;}dfstrave();cout<<Gang.size()<<endl;map<string,int>::iterator it;for(it=Gang.begin();it!=Gang.end();it++){cout<<it->first<<" "<<it->second<<endl;}return 0;
}
采用BFS遍历图
(1)邻接矩阵版
int n,G[maxn][maxn];
bool inq[maxn]={false};
void bfs(int u){queue<int> q;q.push(u);inq[u]=true;while(!q.empty()){int u=q.front();q.pop();for(int v=0;v<n;v++){if(inq[v]==false&&G[u][v]!=INF){q.push(v);inq[v]=true;}}}
}
void bfstrave(){for(int u=0;u<n;u++){if(inq[u]==false){bfs(u);}}
}
(2)邻接表版
vector<int> Adj[maxn];
int n;
bool inq[maxn]={false};
void bfs(int n){queue<int> q;q.push(u);inq[u]=true;while(!q.empty()){int u=q.front;q.pop();for(int i=0;i<Adj[u].size();i++){int v=Adj[u][i];if(inq[v]==false){q.push(v);inq[v]=true;}}}
}
void bfstrave(){for(int u=0;u<n;u++){if(inq[u]==false){bfs(u);}}
}
例题
在微博里,每个用户都可能被若干个其他用户关注。而当该用户发布一条信息时,他的关注者就可以看到这条信息并选择是否转发它,且转发的信息也可以被转发者的关注者再次转发,但同一用户最多只转发该信息一次(信息的最初发布者不会转发该信息)。现在给出N个用户的关注情况(即他们各自关注了哪些用户)以及一个转发层数上限L,并给出最初发布信息的用户编号,求在转发层数上线内信息最多会被多少用户转发。
思路
(1)首先考虑如何建图。由于题目给定的数据是用户关注的情况(而不是被关注的情况),因此如果用户X关注了用户Y,则需要建立由Y指向X的有向边,来表示Y发布的信息可以传递到X并被X转发。
(2)在建图完毕后,使用DFS或者BFS都可以得到需要的结果。如果使用DFS来遍历,只要控制遍历深度不超过题目给定的层数L即可。遍历过程中计数访问到的结点个数(细节处理会比较麻烦)。如果使用BFS来遍历,则需要把结点编号和层号建立成结构体,然后控制遍历层数不超过L
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1010;
struct node{int id;int layer;
};
vector<node> Adj[maxn];
bool inq[maxn]={false};
int bfs(int s,int l){int numForward=0;queue<node> q;node start;start.id=s;start.layer=0;q.push(start);inq[start.id]=true;while(!q.empty()){node topNode=q.front();q.pop();int u=topNode.id;for(int i=0;i<Adj[u].size();i++){node next=Adj[u][i];next.layer=topNode.layer+1;if(inq[next.id]==false&&next.layer<=l){q.push(next);inq[next.id]=true;numForward++;}}}return numForward;
}
int main(){node user;int n,l,numFollow,idFollow;scanf("%d%d",&n,&l);for(int i=1;i<=n;i++){user.id=i;scanf("%d",&numFollow);for(int j=0;j<numFollow;j++){scanf("%d",&idFollow);Adj[idFollow].push_back(user);}}int numQuery,s;scanf("%d",&numQuery);for(int i=0;i<numQuery;i++){memset(inq,false,sizeof(inq));scanf("%d",&s);int numForward=bfs(s,l);printf("%d\n",numForward);}return 0;
}