比较开心 虽然做的时间比较长
这是我第二个做的这种类型的并查集 上一个是 部落
题解(之前的)
难的地方是怎么存数据
单独开一个数组 以每个家族的族长为下标来存数据
在输入的时候的把一个部落的都连在一起
在把人们的祖先用set过一遍去重 set的大小就是部落的个数
注释很详细
DFS(老师又贴了他的代码给我看 我敲了一遍)
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <set>
#include <vector>
#include <map>
using namespace std;
struct node
{
int id, pcnt, rcnt, acnt;
};
//id是int node是id里的信息
map<int, node> info;
//把所有人的id记录 方便下面遍历 所有人
set<int> people;
//放最后每个部落的总答案
vector<node> ans;
//防止重复访问
vector<bool> dp(10000);
//邻接表存图
vector<int> g[10000];
//存图+存人
void addEdge(int x, int y)
{
g[x].push_back(y);
g[y].push_back(x);
people.insert(y);
}
void dfs(int x)
{
//下面循环一次就回把那个人所有的家人访问一遍
auto &i = ans.back();
//找的时候答案就直接放ans里了
i.id = min(i.id, x);
//总人数加
++i.pcnt;
//房子和面积
i.acnt += info[x].acnt;
i.rcnt += info[x].rcnt;
dp[x] = 1;
//在通过这个人x 来访问家人
for (auto e : g[x])
{
if (!dp[e])
dfs(e);
}
}
int main()
{
int N;
cin >> N;
for (int i = 0; i < N; ++i)
{
int x, px, mx, k;
cin >> x >> px >> mx >> k;
people.insert(x);
//把他们都连在一家之主身上
//妈妈和爸爸就没有必要再相连了
//因为他们都连着儿子 就回走通的
if (px != -1)
{
addEdge(x, px);
}
if (mx != -1)
{
addEdge(x, mx);
}
while (k--)
{
int cd;
cin >> cd;
addEdge(x, cd);
}
int r, a;
cin >> r >> a;
//map 通过id索引 id的内容
//而有的人根本没加入map里面
//不过没事 不加的就是0 不影响
info[x] = {x, 1, r, a};
}
//遍历所有人
for (auto e : people)
{
if (!dp[e])
{
//因为要找最小的id 所以一开始给ans一开大的数
ans.push_back({9999, 0, 0, 0});
dfs(e);
}
}
//ans的个数就是部落数了
cout << ans.size() << endl;
//排序规则
auto cmp = [](node e1, node e2) {
double x = e1.acnt * 1.0 / e1.pcnt;
double y = e2.acnt * 1.0 / e2.pcnt;
return x == y ? e1.id < e2.id : x > y;
};
sort(ans.begin(), ans.end(), cmp);
//这几个函数我也写了博客
//在我博客里搜索 输入即可
for (auto i : ans)
{
cout << setw(4) << setfill('0') << i.id << ' ';
cout << i.pcnt << ' ';
cout << fixed << setprecision(3) << i.rcnt * 1.0 / i.pcnt << ' ';
cout << i.acnt * 1.0 / i.pcnt << endl;
}
return 0;
}
并查集
#include <iostream>
#include <numeric>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
struct node
{
int id, t;
double home, s;
} ans[10005];
//ans主要放home和s
//dp里放祖先
vector<int> dp(10005);
int find(int x)
{
return dp[x] == x ? x : dp[x] = find(dp[x]);
}
//并
void uni(int x, int y)
{
//看是不是去世了
if (y == -1 || x == -1)
return;
//看y 之前有没有改过祖先
if (dp[y] == -1)
dp[y] = y;
int a = find(x);
int b = find(y);
if (a != b)
{
dp[b] = a;
}
}
int main()
{
int n;
cin >> n;
//默认为-1
fill(dp.begin(), dp.end(), -1);
//把全部的人放到tt里
//方便下面找祖先 用set主要是去重复的人
set<int> tt;
int m;
for (int i = 0; i < n; ++i)
{
int id;
cin >> id;
// pro.push_back(id);
tt.insert(id);
//看是不是之前没遇到过
//没有的话就弄成自己
if (dp[id] == -1)
dp[id] = id;
for (int i = 0; i < 2; i++)
{
int id_;
cin >> id_;
if (id_ == -1)
continue;
//可以看一下uni里 把id作为祖先
uni(id, id_);
tt.insert(id_);
// pro.push_back(id_);
}
int n1, n2, x;
cin >> n1;
for (int i = 0; i < n1; ++i)
{
cin >> x;
// pro.push_back(x);
tt.insert(x);
uni(id, x);
}
cin >> n2;
//本来我想的是把一个家族的祖先当下标
//把数据存里面 不过发生了一些未知错误
//我懒得找了(找不到啊)
//就在第99行加了两个变量
//因为他们的祖先是不变的 所以:...看下面就知道了
ans[find(id)].home += (double)n2;
cin >> x;
ans[find(id)].s += (double)x;
}
//现在就把家族分好了 主要的工作就是找他们家族对应的id和数据
//home里放的是祖先
//因为祖先的个数是有限的
set<int> home;
//home里放的是各大家族的祖先 为的是对应数据
for (auto e : tt)
{
home.insert(find(e));
}
//home的个数就是家族的个数
cout << home.size() << endl;
//an就是答案了
vector<node> an;
//下面就是找之前存的 面积和房子数
for (auto e : home)
{
double home = 0, st = 0;
int mint = 9999999;
set<int> t;
//t是找个数
for (auto s : tt)
{
if (find(s) == e)
{
home += ans[s].home;
st += ans[s].s;
//找最小的id
mint = min(mint, s);
t.insert(s);
}
}
home /= t.size();
st /= t.size();
an.push_back({mint, (int)t.size(), home, st});
}
sort(an.begin(), an.end(), [](auto e1, auto e2) { if(e1.s==e2.s) return e1.id<e2.id;return e1.s>e2.s; });
for (auto e : an)
{
printf("%04d %d %.3f %.3f\n", e.id, e.t, e.home, e.s);
}
return 0;
}