额。。一看到题目就感觉是用并差距来做,然后思路不是很清晰,还有点畏惧心理,怕麻烦心理。。这样不好不好。其实冷静下来,分析分析,还是蛮好做的
代码写的有点丑。。大概思想是这样的,先考虑有多少个家庭,以编号最小的为father。然后我们可以根据father来知道有几个家庭,然后家庭中的成员数是多少。房子数和面积先放在一个编号上,最后加起来就好了。ps,怎么根据并查集来看有多少个家庭呢?dis[i]==i?那这样的话不是有很多没有出现过的编号也加了进去么。所以我们怎么知道哪些编号我们是出现过的呢,然后我采用的是让dis先初始化为-1,然后出现过了的,我再赋值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
struct node
{
int bh,fz,rs,mj;
};
struct node1
{
int bianhao;
double renjun;
};
node dis[10005];
node1 fina[1005];
int findf(int k)
{
if(dis[k].bh==k)
return k;
else
return k=findf(dis[k].bh);
}
bool cmp(node1 a,node1 b)
{
if(a.renjun!=b.renjun)
return a.renjun>b.renjun;
else
return a.bianhao<b.bianhao;
}
int main()
{
memset(dis,-1,sizeof(dis));
int n;
scanf("%d",&n);
while(n--)
{
int vis[15],visf[15];
memset(visf,0,sizeof(visf));
int me,bb,mm,k,h=1,housenum,s;
scanf("%d %d %d %d",&vis[0],&bb,&mm,&k);
if(bb!=-1)
vis[h++]=bb;
if(mm!=-1)
vis[h++]=mm;
for(int i=1;i<=k;i++)
scanf("%d",&vis[h++]);
for(int i=0;i<h;i++)
if(dis[vis[i]].bh==-1) {dis[vis[i]].bh=vis[i],dis[vis[i]].fz=0,dis[vis[i]].mj=0,dis[vis[i]].rs=1;}
scanf("%d %d",&housenum,&s);
for(int i=0;i<h;i++)
visf[i]=findf(vis[i]);
sort(visf,visf+h);
int father=visf[0];
dis[father].fz+=housenum;
dis[father].mj+=s;
for(int i=0;i<h;i++)
dis[visf[i]].bh=father;
}
int ans=0;
for(int i=0;i<10000;i++)
{
if(dis[i].bh!=-1)
{
int gg=findf(i);
if(gg==i)
{ans++;}
else if(gg!=i)
{
dis[gg].fz+=dis[i].fz;
dis[gg].mj+=dis[i].mj;
dis[gg].rs+=dis[i].rs;
dis[i].bh=gg;
}
}
}
printf("%d\n",ans);
int gd=0;
for(int i=0;i<10000;i++)
if(dis[i].bh==i)
{
fina[gd].renjun=(double)dis[i].mj/dis[i].rs;
fina[gd++].bianhao=i;}
sort(fina,fina+gd,cmp);
for(int i=0;i<gd;i++)
printf("%04d %d %.3f %.3f\n",fina[i].bianhao,dis[fina[i].bianhao].rs,(double)dis[fina[i].bianhao].fz/dis[fina[i].bianhao].rs,(double)dis[fina[i].bianhao].mj/dis[fina[i].bianhao].rs);
return 0;
}