题目翻译:
给定N条通话记录和一个限制K。每条通话记录包含了两个名字和一个通话时间,相互联系的人同属于一个帮派。题目要求,只有人数超过2人并且总通话时长超过K的集体才能算作帮派Gang,并且帮派内部通话时长最长的人是帮派首领Boss。
题解思路:
- 通过两个map,来完成name和id的互相映射,方便哈希查找。
- 再用一个map,来保存头领姓名和帮派人数的,保存答案。
- w[]数组来保存每个人的通话时间,g[][]来保存边的权重,并且方便dfs找到帮派
- 找到新的w更大的结点,head指向该结点,成为新的头领。
- totalweight来记录每个帮派的总通话时间。一定要记住,先遍历边,累加了通话时间,之后一定要把这条边删除。这样一方面避免出现环的情况,造成边权重漏加或者重复加的情况。
代码:
并查集:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 100;
const int M = N * 10 ;
const int mod = 1e9 + 7;
const double eps = 1e-9;
typedef pair<int, int> PII;
#define endl '\n'
#define x first
#define y second
#define INF 0x3f3f3f3f
#define ls(k) k << 1
#define rs(k) k << 1 | 1
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, 1, 0, -1};
int n, m, total;
unordered_map<string, int> num;
unordered_map<int, string> name;
map<string, int> ans;
vector<int> gang[N];
int p[N], w[N], k[N];
void create(string x)
{
if(!num[x])
{
num[x] = ++ total;
name[total] = x;
}
}
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
void merge(int a, int b, int t)
{
int fa = find(a), fb = find(b);
if(fa == fb)
{
k[fa] += t;
return;
}
p[fa] = fb;
k[fb] += k[fa] + t;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++) p[i] = i;
for(int i = 1; i <= n; i ++)
{
string a, b;
int t;
cin >> a >> b >> t;
create(a), create(b);
w[num[a]] += t;
w[num[b]] += t;
merge(num[a], num[b], t);
}
for (int i = 1; i <= total; i ++) gang[find(i)].push_back(i);
for (int i = 1; i <= total; i ++)
{
if(k[i] <= m || gang[i].size() <= 2) continue;
int head = i;
for (auto j : gang[i])
{
if(w[j] > w[head]) head = j;
}
ans[name[head]] = gang[i].size();
}
cout << ans.size() << endl;
for (auto i : ans) cout << i.first << " " << i.second << endl;
return 0;
}
DFS(柳神):
#include <bits/stdc++.h>
using namespace std;
const int maxn=2010;
const int inf=1e8;
map<string,int> nameToid;//姓名转编号
map<int,string> idToname;//编号转姓名
map<string,int> gang; //头领->人数
int n,k,number=0; //通话记录数量,最低时间,总人数
int w[maxn]={0},G[maxn][maxn]={0};
bool vis[maxn]={false};
//遍历节点
void DFS(int now,int &head,int &gangnum,int &totalweight){
gangnum++; //成员数量增加
vis[now]=true; //已经访问过当前结点
if(w[now]>w[head]){
head=now; //找到权重最大的点,成为新的首领
}
for(int i=0;i<number;++i){
if(G[now][i]>0){
totalweight+=G[now][i]; //累加这条边
G[now][i]=G[i][now]=0; //将这两个点之间的边删除
if(!vis[i]){ //如果下一个点还没被访问过,就访问
DFS(i,head,gangnum,totalweight);
}
}
}
}
//遍历整个图
void DFSTrave(){
for(int i=0;i<number;++i){
if(!vis[i]){
int head=i,gangnum=0,totalweight=0; //不要忘了初始化
DFS(i,head,gangnum,totalweight);
if(gangnum>2 && totalweight>k){
//gang是保存name对应人数的
gang[idToname[head]]=gangnum;
}
}
}
}
//完成名字和id的编号,方便查找
int change(string s){
//找到的话,就不需要再添加姓名了
if(nameToid.find(s)!=nameToid.end()){
return nameToid[s];
}else{
nameToid[s]=number;
idToname[number]=s;
return number++;
}
}
int main(){
int weight;
cin >> n>>k;
string s1,s2;
for(int i=0;i<n;++i){
cin >> s1>>s2 >>weight;
int id1=change(s1);
int id2=change(s2);
w[id1]+=weight; //保存到对应的权重里
w[id2]+=weight;
G[id1][id2]+=weight; //保存到邻接矩阵里面
G[id2][id1]+=weight;
}
DFSTrave();
cout << gang.size()<<"\n";
//因为map是按照关键字从小到大输出的,所以不用排序
map<string,int>::iterator it;
for(it=gang.begin();it!=gang.end();++it){
cout << it->first << " "<< it->second<<"\n";
}
return 0;
}
再贴一个看错题(以为姓名只能是AAA这种都一样的形式,最后导致只能过两个点)
#include<bits/stdc++.h>
using namespace std;
map<char, int> p;
map<int, int> c;
int N, K;
int f[1010];
int find(int x)
{
if (x != f[x]) f[x] = find(f[x]);
return f[x];
}
struct node {
int num = 0, sum = 0, index = -1;
};
vector<node> m(26);
bool comp(node n1, node n2)
{
return n1.index < n2.index;
}
int main()
{
cin >> N >> K;
for (int i = 0;i < 26;i++)
p['A' + i] = i;
for (int i = 0;i < 1010;i++)
f[i] = i;
for (int i = 0;i < N;i++)
{
string a, b;
int temp;
cin >> a >> b >> temp;
c[p[a[0]]] += temp;
c[p[b[0]]] += temp;
int x = find(p[a[0]]), y = find(p[b[0]]);
if (x != y) f[y] = x;
}
int cnt = 0;//集合个数
for (int i = 0;i < m.size();i++)
{
m[find(i)].num++;
m[find(i)].sum += c[i];
if (m[find(i)].index == -1 || c[i] > c[m[find(i)].index])
m[find(i)].index = i;
}
sort(m.begin(), m.end(), comp);
for (int i = 0;i < 26;i++)
{
if (m[i].num >= 3 && m[i].sum > K*2)
cnt++;
}
cout << cnt << endl;
for (int i = 0;i < 26;i++)
{
if(m[i].num >= 3 && m[i].sum > K*2)
cout << char(m[i].index + 'A') << char(m[i].index + 'A') << char(m[i].index + 'A') << " " << m[i].num << endl;
}
}
坑点:
无