输入:
10
6666 5551 5552 1 7777 1 100
1234 5678 9012 1 0002 2 300
8888 -1 -1 0 1 1000
2468 0001 0004 1 2222 1 500
7777 6666 -1 0 2 300
3721 -1 -1 1 2333 2 150
9012 -1 -1 3 1236 1235 1234 1 100
1235 5678 9012 0 1 50
2222 1236 2468 2 6661 6662 1 300
2333 -1 3721 3 6661 6662 6663 1 100
输出:
3
8888 1 1.000 1000.000
0001 15 0.600 100.000
5551 4 0.750 100.000
解题思路:
首先我们要对输入的数据进行处理,这里我们是将所有有关系的两个人的编号全部存放到一个二元组中,对于处理出来的二元组,用并查集来进行维护,注意在用并查集进行合并的时候,要将编号大的合并到编号小的节点上,然后将大编号节点上的信息加到小结点上,这样就完成了同一个家庭的合并和信息的更新,然后我们就要遍历所有可能出现过的编号,因此我们要将所有出现过的编号开一个数组额外标记一下,这里的标记主要在两个地方,一个是对二元组里的两个编号分别标记,另一种情况是如果这个家庭中只有一个人,那么这个人在二元组中就不会出现,所以要在输入的时候就要进行标记。
最后将我们需要输出的信息弄成一个结构体,将这些结构体放到一个vector中,然后按照题目要求进行排序,最后输出结果即可。
#include <bitsdc++.h>
using namespace std;
const int N=1e5+10;
int p[N],peo[N],n,idx,tao[N],s[N];
pair<int,int>e[100010];
bool st[N];
struct node{
int bian;
int num;
int tao;
int sq;
};
bool cmp(node a,node b)
{
if((double)a.sq/a.num!=(double)b.sq/b.num)
return (double)a.sq/a.num>(double)b.sq/b.num;
else
return a.bian<b.bian;
}
int find(int x)
{
if(x!=p[x])
p[x]=find(p[x]);
return p[x];
}
void merge(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
int minv=min(fx,fy),maxv=max(fx,fy);
p[maxv]=minv;
peo[minv]+=peo[maxv];
tao[minv]+=tao[maxv];
s[minv]+=s[maxv];
}
}
int main()
{
for(int i=0;i<N;i++)
{
p[i]=i;
peo[i]=1;
}
cin>>n;
int id,fa,ma,k;
for(int i=1;i<=n;i++)
{
cin>>id>>fa>>ma>>k;
if(fa!=-1)
e[++idx]={id,fa};
if(ma!=-1)
e[++idx]={id,ma};
st[id]=true;//有可能这个家庭只有这个人自己
for(int j=1;j<=k;j++)
{
int x;
cin>>x;
e[++idx]={id,x};
}
cin>>tao[id]>>s[id];
}
for(int i=1;i<=idx;i++)
{
merge(e[i].first,e[i].second);
st[e[i].first]=1;
st[e[i].second]=1;
}
vector<node>ans;
for(int i=0;i<N;i++)
if(st[i]&&(p[i]==i))
ans.push_back({i,peo[i],tao[i],s[i]});
sort(ans.begin(),ans.end(),cmp);
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
printf("%04d %d %.3lf %.3lf\n",ans[i].bian,ans[i].num,(double)ans[i].tao/ans[i].num,(double)ans[i].sq/ans[i].num);
return 0;
}