l2 007 家庭房产

        这道题一开始是想使用并查集去做,但是虽然并查集可以将属于同一家庭的人合并到一块,但是这道题目要考虑维护其它信息,在并查集进行合并的时候,可能被合并的成员的信息还没有输入(其实理论上应该也能做),所以我换了一种更加好想的方法。

        25分的正解是使用 建图 加 bfs 来做的。属于同一个家庭的两个人(题目中用编号代替),我们在他们之间建立双向边 。然后遍历每一个人对其使用bfs算法,统计这个人家庭的相关统计信息。同时在bfs算法过程中会对同一家庭中的其他人进行标记,所以当我们遍历过程中这个人被标记过了,那么就跳过这个人。然后得到每一个家庭的统计信息,将其按照题目要求输出。

        还要注意两个点:其一,由于我们是通过枚举整个编号空间来处理的,那么只考虑输入中提到的编号,所以将编号空间的st数组先初始化为0x3f3f3f3f,然后将输入编号对应st中元素初始化为0。

        其二,关于测试点5。由于pta中“4位地址”的含义包括 像0001 0000 这种情况,所以我们在枚举编号空间时,要从0开始枚举(这都卡,好严谨qaq)。

代码如下:

#include<bits/stdc++.h>

using namespace std;
const int N = 1e4 + 10,M = N * 20;

int h[N],e[M],ne[M],idx;
int cnt[N];
int area[N];
int n ;
int st[N];


struct FAM{
	int add;
	int num;
	double cnt;
	double area;
	bool operator<(struct FAM t)const{
		if(area==t.area){
			return add<t.add;
		}
		return area>t.area;
	}
}fam[N];

int top ; 

void add(int a, int b){
	
	e[idx] = b , ne[idx] = h[a] , h[a] = idx ++; 
}


void bfs(int x){
	
	int fcnt = cnt[x];
	int farea = area[x];
	int fnum = 1 ;
	int add = x;
	queue<int> q;
	q.push(x);
	st[x] = 1;
	
	while(q.size()){
		int t = q.front();
	//	cout << x << ' ' << t << endl;
		q.pop();
		for(int i= h[t];i!=-1;i=ne[i]){
			int j = e[i];
			if(st[j]) continue;
			fcnt += cnt[j];
			farea += area[j];
			fnum += 1;
			add = min(add,j);
			q.push(j);
			st[j] = 1;
		}
	}
	fam[top++] = {add,fnum,fcnt * 1.0 / fnum,farea * 1.0 /fnum};
}

int main (){
	cin >> n ;
	
	memset(h,-1,sizeof h);
	memset(st,0x3f,sizeof st);
	for(int i=1;i<=n;i++){
		int addr,fadd,madd;
		int chadd[10];
		int k ;
		cin >> addr >> fadd >> madd;
		st[addr] = st[fadd] = st[madd] = 0 ;
		if(fadd!=-1){
			add(addr,fadd);
			add(fadd,addr);
			
		}
		
		if(madd!=-1){
			add(addr,madd);
			add(madd,addr);			
		}
		
		cin >> k ; 
		
		for(int i=1;i<=k;i++){
			cin >> chadd[i];
			st[chadd[i]] = 0 ;
			add(addr,chadd[i]);
			add(chadd[i],addr);
		}
		
		int tcnt,tarea;
		cin >> tcnt >> tarea;
		cnt[addr] = tcnt;
		area[addr] = tarea;
	}	
	
	for(int i = 1;i<=9999;i++){
		if(st[i]) continue;
		bfs(i);
	}
	
	cout << top << endl;
	sort(fam,fam+top);
	
	for(int i=0;i<top;i++){
		auto t = fam[i];
		printf("%04d %d %.3lf %.3lf\n",t.add,t.num,t.cnt,t.area);
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值