[PAT解题报告] Head of a Gang
题目给了个很好的背景,就是人物之间打电话。人可以看作节点,边可以看作通话时间,图是无向的。定义一个连通分量可能就是一个团伙,还需要看
(1) 连通分量里的节点数 大于1
(2) 边总权值大于一个阈值K
这个都很简单,我们对于每个点,求连通分量,顺便打上标号(我写的where)就表示它在哪个分量里,按照联通分量标号排序,同一个连通分量的点在一起。求连通分量可以用dfs,顺便求出每个点连边权的总和,也能求出分量里所有边权值和——别忘记除以2和K比较。这样就能找到团伙。排序时同一个团伙把连边权和大的节点放在前面,就能找到每个团伙的头。
还要注意字符串到整数id之间使用map直接映射就好了。
代码:
#include <cstdio> #include <cstring> #include <string> #include <map> #include <set> #include <algorithm> using namespace std; struct node { char name[4]; int where; int weight; }; map<string,int> id; int a[2048][2048]; node p[2048]; char s[10]; int n; set<pair<string,int> > all; bool cmp(const node &a, const node &b) { return (a.where < b.where) || ((a.where == b.where) && (a.weight > b.weight)); } int give(char *name) { map<string,int>::iterator t = id.find(name); if (t == id.end()) { int r = id.size(); strcpy(p[r].name, name); p[r].weight = 0; p[r].where = -1; return id[name] = r; } return t->second; } void dfs(int x, int y) { if (p[x].where >= 0) { return; } p[x].where = y; for (int i = 0; i < n; ++i) { if (a[x][i]) { p[x].weight += a[x][i]; dfs(i, y); } } } int main() { int k; scanf("%d%d",&n,&k); for (int i = 0; i < n; ++i) { scanf("%s",s); int x = give(s), len; scanf("%s%d",s,&len); int y = give(s); a[x][y] += len; a[y][x] += len; } n = id.size(); for (int i = 0; i < n; ++i) { dfs(i, i); } sort(p, p + n, cmp); for (int i = 0; i < n; ) { int total = 0, j; for (j = i; (i < n) && (p[j].where == p[i].where); total += p[i++].weight) ; if ((i - j > 2) && ((total >> 1) > k)) { all.insert(make_pair((string) p[j].name, i - j)); } } printf("%d\n",all.size()); for (set<pair<string,int> >::iterator t = all.begin(); t != all.end(); ++t) { printf("%s %d\n",t->first.c_str(), t->second); } return 0; }
原题链接: http://www.patest.cn/contests/pat-a-practise/1034