1013.战争中的城市

KM<3500000,根据时间复杂度,对于K次询问,每次很可能是去遍历每一条边
除去一个节点后,初始状态应当有n-1个集合
,我们对于每一次询问,遍历每一条边,并且将没有在一个集合内的点相互合并,每次合并之后,集合数目减一,最后需要连通的边数就是集合数目减一
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=1010,M=500010;
int n,m,k;
int p[N];
struct Edge{
int a,b;
}edge[M];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main(){
scanf("%d %d %d",&n,&m,&k);
for(int i=0;i<m;i++){
scanf("%d %d",&edge[i].a,&edge[i].b);
}
while(k--){
int x;
cin>>x;
for(int i=1;i<=n;i++)p[i]=i;
int cnt=n-1;
for(int i=0;i<m;i++){
int a=edge[i].a,b=edge[i].b;
if(a!=x && b!=x){
int pa =find(a),pb=find(b);
if(pa!=pb){
p[pa]=pb;
cnt--;
}
}
}
cout<<cnt-1<<endl;
}
}
1114.家产 **

- 考虑到最多有1000组输入而每个人最多有7个亲人,所以最多的人数在7000人
- 首先建立好每条边(
即根据输入在每一个有关联的人之间建立一条边,最多7000条
) - 其次遍历每一条边,用并查集合并集合,
每次合并都将根节点序号更大的集合合并到根节点更小的 集合
- 维护根节点的数据
即当前家庭的数据(包括人数,房产数,房产面积)
- 按照要求排序输出
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>
#include<vector>
using namespace std;
const int N=1e4+10;
int p[N],c[N],hv[N],ha[N];
int n;
bool st[N];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
struct Edges{
int a,b;
}edge[N];
struct Family{
int id,c,hv,ha;
bool operator < (const Family & t)const {
if(ha * t.c != t.ha * c) return ha*t.c > t.ha*c;
else return id< t.id;
}
};
int main(){
cin>>n;
int cnt=0;
while(n--){
int id,father,mother,k;
cin>>id>>father>>mother>>k;
st[id]=true;
if(father!=-1)edge[cnt++]={id,father};
if(mother!=-1)edge[cnt++]={id,mother};
for(int i=0;i<k;i++){
int son ;
cin>>son;
edge[cnt++]={id,son};
}
cin>>hv[id]>>ha[id];
}
for(int i=0;i<N;i++)p[i]=i,c[i]=1;
for(int i=0;i<cnt;i++){
int a=edge[i].a,b=edge[i].b;
int pa=find(a),pb=find(b);
st[a]=st[b]=true;
if(pa!=pb){
if(pb>pa)swap(pa,pb);
c[pb]+=c[pa];
hv[pb]+=hv[pa];
ha[pb]+=ha[pa];
p[pa]=pb;
}
}
vector<Family> family;
for(int i=0;i<N;i++){
if(st[i] && p[i]==i)family.push_back({i,c[i],hv[i],ha[i]});
}
sort(family.begin(),family.end());
cout<<family.size()<<endl;
for(auto it :family){
printf("%04d %d %.3lf %.3lf\n",it.id,it.c,(double)it.hv/it.c,(double)it.ha/it.c);
}
}
1118.森林里的鸟

#include<iostream>
#include<cstring>
using namespace std;
const int N=1e4+10;
int n;
int p[N],birds[10];
bool st[N];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main(){
scanf("%d",&n);
for(int i=1;i<N;i++)p[i]=i;
while(n--){
int k;
scanf("%d",&k);
for(int i=0;i<k;i++){
scanf("%d",&birds[i]);
st[birds[i]]=true;
}
for(int i=1;i<k;i++){
int a=birds[i-1],b=birds[i];
int pa=find(a),pb=find(b);
if(pa!=pb)p[pa]=pb;
}
}
int res=0,cnt=0;
for(int i=1;i<N;i++){
if(st[i]){
cnt++;
if(p[i]==i)res++;
}
}
cout<<res<<" "<<cnt<<endl;
int q;
scanf("%d",&q);
while(q--){
int a,b;
scanf("%d %d",&a,&b);
int pa=find(a),pb=find(b);
if(pa!=pb)cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
1107.社会集群 **

- 首先将数据读入到邻接表中,
该邻接表表头为所有爱好编号,成员为拥有该爱好的人的序号
- 然后根据所有具有相同爱好的人进行合并集合
- 最后遍历并查集,找出总集合数目
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1010;
vector<int> hobby[N];
int p[N],cnt[N];
bool st[N];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)p[i]=i,cnt[i]=1;
for(int i=1;i<=n;i++){
int k;
scanf("%d:",&k);
while(k--){
int x;
scanf("%d", &x);
hobby[x].push_back(i);
}
}
int res=0;
vector<int> nums;
for(int i=1;i<=1000;i++)
for(int j=1;j<hobby[i].size();j++){
int a=hobby[i][0],b=hobby[i][j];
int pa=find(a),pb=find(b);
if(pa!=pb){
cnt[pa]+=cnt[pb];
p[pb]=pa;
}
}
for(int i=1;i<=n;i++){
if(p[i]==i){
res++;
nums.push_back(cnt[i]);
}
}
sort(nums.begin(),nums.end(),greater<int> ());
cout<<res<<endl;
cout<<nums[0];
for(int i=1;i<nums.size();i++)cout<<" "<<nums[i];
}