Head of a Gang
dfs求连通子图:
1.通过dfs来遍历所有成员,将所有有通话记录的成员放在同一个团伙中(求连通子图),注意用结构体来储存团伙信息(团伙中用vector容器来储存内含成员)。
2.用<string,int>的unordered_map来形成名字对序号的映射,用<int,string>的unordered_map来方便查询。
#include<iostream>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
unordered_map<string,int> Map1;
unordered_map<int,string> Map2;
vector<int> v[2001];
int N,K,minute[2001],visited[2001]={0};
int cursor=0;//cursor是有效团伙计数标志
//因为团伙涉及头领,总时长,成员,所以采用结构体储存团伙数据
struct gang{
int head;
int total_minute=0;
vector<int> member;
};
gang gangs[2001];
void dfs(int cur){
if(visited[cur]!=0) return;
gangs[cursor].member.emplace_back(cur);
gangs[cursor].total_minute+=minute[cur];
visited[cur]=1;
for(int each : v[cur]){
dfs(each);
}
}
bool comp(gang x,gang y){
return Map2[x.head]<Map2[y.head];
}
int main(){
int i,j,k,t;
string s1,s2;
//数据读入
cin>>N>>K;
for(i=0;i<N;i++){
cin>>s1>>s2>>t;
//处理S1映射序号
if(Map1.count(s1)) j=Map1[s1];//如果名字已经存在于Map1中,直接把序号取出来
else{//如果名字不存在与Map1中,给名字赋序号Map1.size()+1
j=Map1[s1]=Map1.size()+1;
Map2[j]=s1;
}
//处理S2映射序号
if(Map1.count(s2)) k=Map1[s2];
else{
k=Map1[s2]=Map1.size()+1;
Map2[k]=s2;
}
v[j].emplace_back(k);
v[k].emplace_back(j);
minute[j]+=t;
minute[k]+=t;
}
//实验处理
for(i=1;i<=N;i++){
if(visited[i]!=0) continue;
//因为只有能判断为团伙cursor才会++,如果不满足条件,需要清空member及total_minute
gangs[cursor].member.clear();
gangs[cursor].total_minute=0;
dfs(i);
if(gangs[cursor].member.size()>2 && gangs[cursor].total_minute>K*2){
int maxminute=0;
for(int each : gangs[cursor].member){
if(maxminute<minute[each]){
maxminute=minute[each];
gangs[cursor].head=each;
}
}
cursor++;
}
}
//首领名字按照字典序排序
sort(gangs,gangs+cursor,comp);
cout<<cursor<<endl;
for(i=0;i<cursor;i++){
cout<<Map2[gangs[i].head]<<' '<<gangs[i].member.size()<<endl;
}
return 0;
}
并查集做法:
#include<iostream>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
unordered_map<string, int> m1;
unordered_map<int, string> m2;
int book[2001] = { 0 }, minute[2001];
int N, K;
struct gangs {
int head;
vector<int> member;
int totalminute = 0;
}gang[2001];
bool comp(gangs x,gangs y){
return m2[x.head]<m2[y.head];
}
int getf(int v) {
if (book[v] == v) {
return v;
}
else {
book[v] = getf(book[v]);//路径压缩
return book[v];
}
}
void merge(int v, int u) {
int t1, t2;
t1 = getf(v);
t2 = getf(u);
if (t1 != t2) book[t2] = t1;//靠左原则,将左边变成右边的老大
return;
}
int main() {
cin >> N >> K;
string s1, s2;
int t, i, j, k;
//值初始化为序号
for (i = 1; i <= N; i++) book[i] = i;
//并查集操作
for (i = 0; i < N; i++) {
cin >> s1 >> s2 >> t;
if (m1.count(s1)) j = m1[s1];
else {
j = m1[s1] = m1.size() + 1;
m2[j] = s1;
}
if (m1.count(s2)) k = m1[s2];
else {
k = m1[s2] = m1.size() + 1;
m2[k] = s2;
}
merge(j, k);
minute[j] += t;
minute[k] += t;
}
int cursor = 0;
for (i = 1; i <= N; i++) {
int maxminute = 0, maxboss;
//boo[i]=i的就是老大,统计老大有多少个小弟及计算团伙总通话时长
if (book[i] == i) {
gang[cursor].member.clear();
gang[cursor].totalminute = 0;
for (j = 1; j <= N; j++) {
if (book[j] == i) {
gang[cursor].member.emplace_back(j);
gang[cursor].totalminute += minute[j];
if (minute[j] > maxminute) {
maxminute = minute[j];
maxboss = j;
}
}
}
if (gang[cursor].member.size() > 2 && gang[cursor].totalminute > 2 * K) {
gang[cursor].head = maxboss;
cursor++;//在能确定是一个团伙的情况下再给cursor++
}
}
}
sort(gang,gang+cursor,comp);
cout << cursor;
for (i = 0; i < cursor; i++) {
cout <<endl<< m2[gang[i].head] << ' ' << gang[i].member.size();
}
return 0;
}