额。。一看到题目就感觉是用并差距来做,然后思路不是很清晰,还有点畏惧心理,怕麻烦心理。。这样不好不好。其实冷静下来,分析分析,还是蛮好做的 代码写的有点丑。。大概思想是这样的,先考虑有多少个家庭,以编号最小的为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("d %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; }