A1034 Head of a Gang (30point(s))
图或者并查集
题意
寻找可疑的犯罪团伙按照字母顺序输出首领的name。
可疑的犯罪团伙指在一个边权加起来大于K并且节点个数大于2的连通图。
首领是边权总和最大的那个。
思路
首先是名字和节点对应的问题,这里用map<string,int> 解决。
然后边权直接加到点权上面,判断时除以二即可。
显然,也可以用并查集。
总结
这题最关键的一点是记录小于1000,但是maxn要设置为2000。
Sample Input:
8 59
AAA BBB 10
BBB AAA 20
AAA CCC 40
DDD EEE 5
EEE DDD 70
FFF GGG 30
GGG HHH 20
HHH FFF 10
Sample Output:
2
AAA 3
GGG 3
#include"bits/stdc++.h"
using namespace std;
struct Node {
string name;
vector<int> links;
int w = 0;
};
const int maxn = 2010;
Node nodes[maxn];
int vis[maxn];
int bfs(int id,int k,int &cnt_num) {
queue<int> q;
q.push(id);
cnt_num = 0;
int cnt_w = 0;
bool ok = false;
int id_max = 0;
int w_max = 0;
while(!q.empty()) {
int idt = q.front();
vis[idt] = 1;
q.pop();
cnt_num ++;
cnt_w += nodes[idt].w;
if(cnt_num > 2 && cnt_w > 2*k) {
ok = true;
}
if(nodes[idt].w > w_max) {
w_max = nodes[idt].w;
id_max = idt;
}
for(int t:nodes[idt].links){
if(vis[t]) continue;
q.push(t);
vis[t] = 1;
}
}
return ok ? id_max : -1;
}
int main() {
freopen("input.txt","r",stdin);
int n,k;
cin >> n >> k;
map<string,int> name2id;
for(int i=0; i<n; i++) {
string s1,s2;
int t;
cin >> s1 >> s2 >> t;
if(!name2id.count(s1)) {
name2id[s1] = name2id.size();
nodes[name2id[s1]].name.assign(s1);
}
if(!name2id.count(s2)){
name2id[s2] = name2id.size();
nodes[name2id[s2]].name.assign(s2);
}
int t1 = name2id[s1];
int t2 = name2id[s2];
nodes[t1].w += t;
nodes[t2].w += t;
nodes[t1].links.push_back(t2);
nodes[t2].links.push_back(t1);
}
fill(vis,vis+maxn,0);
vector<pair<string,int>> ans;
for(int i=0; i<name2id.size(); i++) {
if(vis[i]) continue;
int num = 0;
int t = bfs(i,k,num);
if(t != -1) {
ans.push_back(make_pair(nodes[t].name,num));
}
}
sort(ans.begin(),ans.end(),
[](pair<string,int>& p1,pair<string,int>& p2){
return p1.first < p2.first;
});
cout << ans.size() << endl;
for(int i=0;i<ans.size();i++){
cout << ans[i].first << " " << ans[i].second << endl;
}
}