思路
这道题就是维护多个集合的并查集,每次合并的时候记得更新以下集合,并且注意集合的初始化
size: 家庭人口总数
cnt1:家庭房产总数
area:家庭房产总面积
mi:家庭成员最小编号
思路上有困难的,欢迎友好交流~
易错点分析
有可能编号为0000,容易错测试点3
AC代码
#include<bits/stdc++.h>
#define vec vector<int>
#define endl '\n'
using namespace std;
const int N =1e4+9;
const double eps=1e-6;
int p[N];
int size[N];//家庭人数
int cnt1[N]; // 家庭房产总数
int mi[N]; //家庭成员编号最小
bool flag[N];//判断是否在输入中
double area[N];//家庭房产总面积
int Find(int x)
{
if(x!=p[x]) p[x]=Find(p[x]);
return p[x];
}
struct node1
{
int id,num;
double n1,a1;
bool operator<(const node1 &t) const
{
if(fabs(a1-t.a1)>eps) return a1>t.a1;
else return id<t.id;
}
}e[N];
//合并操作
void Union(int a,int b)//第一个是输入的id
{
int fa=Find(a);
int fb=Find(b);
if(fa!=fb)//都往id所在集合加
{
mi[fa]=min(mi[fa],mi[fb]);
size[fa]+=size[fb];
area[fa]+=area[fb];
cnt1[fa]+=cnt1[fb];
p[fb]=fa;
}
}
int main()
{
int n;
cin>>n;
//注意初始化
for(int i=0; i<=N; i++) p[i]=i,size[i]=1,mi[i]=i;
for(int i=0; i<n; i++)
{
int id,f,m,k;
cin>>id>>f>>m>>k;
flag[Find(id)]=true;
if(f!=-1)
{
if(Find(id)!=Find(f)) Union(id,f);
}
if(m!=-1)
{
if(Find(id)!=Find(m)) Union(id,m);
}
for(int j=0; j<k; j++)
{
int x;
cin>>x;
if(Find(id)!=Find(x)) Union(id,x);
}
int num;
cin>>num;
double sum=0;
cnt1[Find(id)]+=num;//家庭
if(num) cin>>sum;
area[Find(id)]+=sum;//家庭房产总面积
}
int t=0;
//注意编号可能为0
for(int i=0; i<=N; i++)
{
//if(Find(i)==Find(1)) cout<<i<<endl;
int fi=Find(i);
if(fi==i&&flag[fi])
{
e[t++]={mi[fi],size[fi],cnt1[fi]*1.0/size[fi],area[fi]/size[fi]};
}
}
sort(e,e+t);
cout<<t<<endl;
for(int i=0; i<t; i++)
{
printf("%04d %d %.3f %.3f\n",e[i].id,e[i].num,e[i].n1,e[i].a1);
}
return 0;
}