天梯赛 L2-007 家庭房产

先是自己使用并查集+map进行大模拟写了一份很麻烦的代码,一直过不去测试点3和4,结果是因为使用了ios::sync_with_stdio(0),cin.tie(0),cout.tie(0),导致不能让程序在输入输出中同时使用了C++的输入输出流和C标准库的输入输出函数,后来注释掉就过了,代码如下:

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef long long ll;
const int N = 10100;
const int mod = 998244353;
int parent[N],n;
struct box{
	int id;
	int num;
	int hous;
	int area;
};
int find(int x){
	if(parent[x] != x){
		parent[x] = find(parent[x]);
	}
	return parent[x];
}
void merge(int x,int y){
	parent[find(x)] = find(y);
}
bool cmp(box x,box y){
	if(x.area * y.num == y.area * x.num){
		return x.id < y.id;
	}
	return x.area * y.num > y.area * x.num;
}
void solve() {
	//并查集初始化
	for(int i = 0 ; i <= 10000; i++){
		parent[i] = i;
	}
	cin>>n;
	map<int,pair<int,int>> value;
	map<int,int> tmp;
	for(int i = 0 ; i < n; i++){
		int bh,fa,ma;
		cin>>bh>>fa>>ma;
		tmp[bh];
		if(fa != -1){
			merge(bh,fa);
			tmp[fa];
		}
		if(ma != -1){
			merge(bh,ma);
			tmp[ma];
		}
		int k;
		cin>>k;
		for(int i = 0 ; i < k ; i++){
			int x;
			cin>>x;
			tmp[x];
			merge(bh,x);
		}
		int fz,mj;
		cin>>fz>>mj;
		value[bh].first = fz;
		value[bh].second = mj;
	}
	map<int,int> fam,minans,h1,a1;
	int cnt = 0;
 //    for(auto it : tmp){
	// 	minans[find(it.first)] == -1;
	// }
	map<int,int> vt;
	for(auto it : tmp){
		fam[find(it.first)]++;
		h1[find(it.first)] += value[it.first].first;
		a1[find(it.first)] += value[it.first].second;
		if(vt[find(it.first)] == 0){
			vt[find(it.first)] = 1;
			minans[find(it.first)] = it.first;
		}else minans[find(it.first)] = min(it.first,minans[find(it.first)]);
	}
	vector<box> ans;
	for(auto it : minans){
		ans.push_back({it.second,fam[find(it.first)],h1[find(it.first)],a1[find(it.first)]});
	}
	cnt = fam.size();
	cout<<cnt<<endl;
	sort(ans.begin(),ans.end(),cmp);
	for(int i = 0 ; i < ans.size() ; i++){
		printf("%04d %d %.3lf %.3lf\n",ans[i].id,ans[i].num,ans[i].hous*1.0/ans[i].num
		,ans[i].area*1.0/ans[i].num);
	}
}
signed main() {
    // ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int tt = 1;
    //    cin >> tt;
    while (tt--) {
        solve();
    }
    return 0;
}

看了一个讲解视频后,学到了并查集的带权合并,就是额外开几个数组,合并的时候把对应的value也加上即可,注意我们要让最小的成为一个并查集(家庭)的代表,所以在合并的时候就判断一下,如果xx  > yy 就交换,还要注意的是,因为代码中fa没有初始化,默认全为0,所以需要对0进行特殊处理,不然默认fx[0=0,导致如果没有0,结果却有0,所以,我们就初始化fa[0] = -1,还需要在find中对0进行特判,防止越界。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef long long ll;
const int N = 10100;
const int mod = 998244353;
int fa[N],pnum[N],hnum[N],anum[N];
vector<int> ship[N];
int find(int x){
	if(fa[x] == -1) return -1;
	if(x == fa[x]){
		return x;
	}
	else return fa[x] = find(fa[x]);
}
void merge(int x,int y){
	int xx = find(x),yy = find(y);
	if(xx == yy) return;
	if(xx > yy) swap(xx,yy);	//保证代表这个家庭的是最小的
	fa[yy] = xx;
	pnum[xx] += pnum[yy];
	hnum[xx] += hnum[yy];
	anum[xx] += anum[yy];
	return; 
}
struct box{
	int id,p_num,h_num,a_num;
	double per1,per2;
	bool operator < (const box &t) const{
		if(per2 != t.per2) return per2 > t.per2;
		else return id < t.id;
	}
};
vector<box> ans;
void solve() {
	int n;
	cin>>n;
	fa[0] = -1;	//特殊处理0,
	for(int i = 1 ; i <= n ; i++){
		int tid,dad,mom,sonk,son;
		cin>>tid>>dad>>mom>>sonk;
		for(int j = 1 ; j <= sonk ; j++){
			cin>>son;
			ship[tid].push_back(son);
			fa[son] = son;
			pnum[son] = 1;
		}
		if(dad != -1){
			ship[tid].push_back(dad);
			fa[dad] = dad;
			pnum[dad] = 1;
		}
		if(mom != -1){
			ship[tid].push_back(mom);
			fa[mom] = mom;
			pnum[mom] = 1;
		}
		fa[tid] = tid,pnum[tid] = 1;
		cin>>hnum[tid]>>anum[tid];
	}
	for(int i = 0 ; i < 10000 ; i++){
		for(int j = 0 ; j < ship[i].size() ; j++){
			merge(i,ship[i][j]);	//执行合并操作
		}
	}
	for(int i = 0 ; i < 10000 ; i++){
		if(i == find(i)){
			ans.push_back({i,pnum[i],hnum[i],anum[i],
			hnum[i]*1.0/pnum[i],anum[i]*1.0/pnum[i]});
		}
	}
	sort(ans.begin(),ans.end());
	cout<<ans.size()<<endl;
	for(int i = 0 ; i < ans.size() ; i++){
		printf("%04lld %lld %.3lf %.3lf\n",ans[i].id,
		ans[i].p_num,ans[i].per1,ans[i].per2);
	}
}
signed main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int tt = 1;
    //    cin >> tt;
    while (tt--) {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值