题解:P14501 [NCPC 2025] Gotta Trade Some of 'Em
zybgml_AFO · · 题解
题号:P14501
题目链接:P14501 [NCPC 2025] Gotta Trade Some of 'Em
题目简述:
题目给我们
思路:
这道题很显然,是一道并查集的板子题。
为什么呢?因为我们想一下:
如果孩子
那么孩子
也就是说可以将孩子
那么我们就要用到 并查集 了。
并查集
这是 oiwiki 里并查集的定义:
并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。
其实就是给数分了个组。用一个数组来存储这个点所属的集的编号。
并查集可以实现两种操作:
1.查
假如有一个数组,我们我们定义
并查集是需要初始化的,就把数组中的每一个数的集合编号都赋值为下表就可以了。
我们会在下面涉及到并的操作,使某些数的集合编号改变。所以我们用以下函数实现查的操作:
inline int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
这是什么意思呢?
意思是如果
可如果不一样,说明它现在的集合编号所在的集合改变了,需要再次查找
2.并
现在我们想要将第
第一步是先判断一下这两个数是否处于同一集合。如果不是,再进行下一步操作:
将第
构造答案
我们现在处理完
为了让每一个小孩都可以收集到所有版本中的 Pokémon,我们尽量让每个集合内的小孩拥有的 Pokémon 版本不一致。下面有一个例子可供理解:
假设有
可如果有
这就是判断如果不存在任何分配方式可以使所有孩子填满 Pokédex 的方法:
如果有解,我们就让集合中前
代码:
#include<bits/stdc++.h>
typedef long long ll;
template<typename T>inline void read(T&x){
x=0;char c;int sign=1;
do{c=getchar();if(c=='-') sign=-1;}while(!isdigit(c));
do{x=x*10+c-'0';c=getchar();}while(isdigit(c));
x*=sign;
}
int n,m,k;
int x,y;
int f[100005],z[100005],c[100005];
inline int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}//查
int main(){
read(n),read(m),read(k);
for(int i=1;i<=n;i++) f[i]=i;
while(m--){
read(x),read(y);
if(find(x)!=find(y)) f[find(x)]=find(y);//并
}
for(int i=1;i<=n;i++) z[find(i)]++;//计算集合编号为 find(i) 的集合中的元素数量
for(int i=1;i<=n;i++){
if(z[i]&&z[i]<k){//判断是否有解
printf("impossible");
return 0;
}
}
for(int i=1;i<=n;i++){
if(c[f[i]]==k) c[f[i]]=0;//避免版本号越界
printf("%d ",++c[f[i]]);//输出
}
return 0;
}
代码总结:
代码不难,并查集 的题都挺简单的。
题目总结:
这道题涉及 并查集。比较简单,可以用来练练手,刷刷手感。