#include<bits/stdc++.h>
using namespace std;
/*并查集,开辟一个大数组*/
const int MAXN=1000001;
int father[MAXN];
int appear[MAXN];//1表示appear[i]出现过
void Initial()
{
for(int i=0;i<MAXN;i++)
{
father[i]=-1;
appear[i]=0;
}
}
int Find(int x)
{
while(father[x]!=-1)
x=father[x];
return x;
}
void Union(int x,int y)//根节点的合并集合
{
x=Find(x);
y=Find(y);
if(x!=y)
father[y]=x;
return ;
}
int main()
{
int x,y;
Initial();
while(cin>>x>>y)
{
Union(x,y);
appear[x]=1;
appear[y]=1;
//x和y出现过则置为1
}
int component=0;
for(int i=0;i<MAXN;i++)
if(appear[i]==1&&father[i]==-1)
component++;
//因为之前合并过集合所以father[i]==-1说明有一个连通分量,且要出现过
cout<<component<<endl;
return 0;
} #include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstring>
#include <sstream>
#include<map>
using namespace std;
int fa[1000005];
bool vis[1000005];
int get(int root){
if(fa[root]==root)
return root;
else
return fa[root]=get(fa[root]);
}
int main(){
int a,b;
memset(vis,0,sizeof(vis));
for(int i=0;i<=1000000;i++)
fa[i]=i;
while(cin>>a>>b){
vis[a]=true;
vis[b]=true;
a=get(a);
b=get(b);
fa[a]=b;
}
int ans=0;
for(int i=0;i<=1000000;i++){
if(vis[i]==true){
if(fa[i]==i)
ans++;
}
}
cout<<ans<<endl;
} /*
*根据输入的数据生成并查集 , 然后查询根节点的个数
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
int father[maxn+5];
void Initial() //初始化父节点数组
{
for(int i = 0;i < maxn; i++) father[i] = i;
}
int getFather(int x) //找到根节点
{
int a = x;
while(x != father[x]) x = father[x];
//路径压缩
while(a != father[a])
{
int z = a; a = father[a]; father[z] = x;
}
return x;
}
void Union(int a, int b) //合并
{
int fa = getFather(a);
int fb = getFather(b);
if(fa != fb) father[fa] = fb;
}
int main()
{
ios::sync_with_stdio(false);
int a, b; set<int> s;
Initial();
while(cin >> a >> b)
{
Union(a, b); s.insert(a); s.insert(b);
}
int ans = 0;
for(int i : s) ans += father[i] == i? 1 : 0;
cout << ans << "\n";
return 0;
} #include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
map <int,int> table;
int find(int x){
if(table.find(x)==table.end()||table[x]==x){
return x;
}
else{
table[x]=find(table[x]); //路径压缩
}
return table[x]
}
int main()
{
int a,b;
while(cin>>a>>b){ //读入数据,构建并查集
if(a==0){
break;
}
a=find(a);
b=find(b);
table[a]=b;
table[b]=b;
}
map<int,int>::iterator iter;
int count=0;
for(iter=table.begin();iter!=table.end();iter++){
if(iter->second==iter->first){
count++;
}
}
cout<<count<<'\n';
} #include<bits/stdc++.h>
using namespace std;
void dfs(bool vis[], map<int, set<int> > &ms, int i)
{
vis[i] = 1;
for(auto mi=ms[i].begin(); mi!=ms[i].end(); mi++){
if(!vis[*mi]){
dfs(vis, ms, *mi);
}
}
}
int main()
{
map<int, int> m;
map<int, set<int> > ms;
int a, b, cnt = 0;
while(cin>>a>>b){
if(m.find(a) == m.end()){
m[a] = cnt++;
set<int> s;
ms[m[a]] = s;
}
if(m.find(b) == m.end()){
m[b] = cnt++;
set<int> s;
ms[m[b]] = s;
}
if(a != b){
ms[m[a]].insert(m[b]);
ms[m[b]].insert(m[a]);
}
}
bool vis[cnt];
memset(vis, 0, sizeof(vis));
int res = 0;
for(int i=0; i<cnt; i++){
if(!vis[i]){
res++;
dfs(vis, ms, i);
}
}
cout<<res;
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <stack>
#include <cmath>
#include <map>
#include <vector>
#include <set>
using namespace std;
map<int, bool> visit;
map<int, vector<int> > mp;
void dfs(int x)
{
visit[x] = 1;
for(int i = 0;i<mp[x].size();i++)
{
if(!visit[mp[x][i]])
dfs(mp[x][i]);
}
}
int main()
{
visit.clear();
mp.clear();
set<int> st;
st.clear();
int x,y;
while(cin >> x >> y)
{
st.insert(x);
st.insert(y);
mp[x].push_back(y);
mp[y].push_back(x);
}
int ans = 0 ;
for(set<int>::iterator it = st.begin() ; it != st.end(); ++it)
{
if(visit[*it] == 0)
{
ans++;
dfs(*it);
}
}
cout << ans << endl;
} /*
DFS
1.只有有边的点参与计算联通分支数,所以将vis默认为true,当有输入边时,设顶点为false,就可以只考虑有边的顶点的DFS。
2.顶点最大数量MAXN至少设置1000010。100010都不行。
*/
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
const int MAXN=1000010;
vector<int> Adj[MAXN];
bool vis[MAXN];
void DFS(int u)
{
vis[u]=true;
for(int i=0;i<Adj[u].size();i++)
{
int v=Adj[u][i];
if(vis[v]==false)
DFS(v);
}
}
int main()
{
fill(vis,vis+MAXN,true);
int v1,v2;
while(scanf("%d%d",&v1,&v2)!=EOF)
{
Adj[v1].push_back(v2);
Adj[v2].push_back(v1);
//只有有边的点参与计算联通分支数
vis[v1]=vis[v2]=false;
}
int count=0;
for(int i=0;i<MAXN;i++)
{
if(vis[i]==false)
{
DFS(i);
count++;
}
}
printf("%d\n",count);
return 0;
} #include <iostream>
#include <set>
using namespace std;
#define N 1000000
int Tree[N];
int findRoot(int x){
if(Tree[x]==-1) return x;
int temp=findRoot(Tree[x]);
Tree[x]=temp;
return temp;
}
int main(){
int a,b;
set<int>s;
for(int i=0;i<N;i++) Tree[i]=-1;
while(cin>>a>>b){
s.insert(a);
s.insert(b);
a=findRoot(a);
b=findRoot(b);
if(a!=b) Tree[a]=b;
}
int ans=0;
set<int>::iterator it;
for(it=s.begin ();it!=s.end ();it++)
if(Tree[*it]==-1) ans++;
cout<<ans<<endl;
return 0;
}
//const int MAX=1000010;
#include<iostream>
(720)#include<cstdio>
using namespace std;
const int MAX=1000010;
int father[MAX];
int height[MAX];
bool visit[MAX];
void Init(){
for(int i=1;i<MAX;i++){
father[i]=i;
height[i]=0;
visit[MAX]=false;
}
}
int Find(int x){
if(x!=father[x]){
father[x]=Find(father[x]);
}
return father[x];
}
void Union(int x,int y){
x=Find(x);
y=Find(y);
if(x!=y){
if(height[x]<height[y]){
father[x]=y;
}else if(height[x]>height[y]){
father[y]=x;
}else{
father[y]=x;
height[x]++;
}
}
}
int main(){
Init();
int MaxNum=0;
int x,y;
while(scanf("%d%d",&x,&y)!=EOF){
Union(x,y);
visit[x]=true;
visit[y]=true;
MaxNum=MaxNum>x?MaxNum:x;//为了缩小下面的遍历范围 保留这一个文件中最大编号的节点
MaxNum=MaxNum>y?MaxNum:y;
}
int component=0;
for(int i=1;i<=MaxNum;i++){
if(!visit[i])
continue;
if(father[i]==i)
component++;
}
printf("%d\n",component);
return 0;
} #include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
map<int,int> father; //通过散列表map实现的father数组
map<int,int> height; //记录每个节点的高度
int find(int x){
if(father.find(x)!=father.end()){
if(father[x]!=x)
father[x]=find(father[x]); //路径压缩(最后自己通过例子模拟下过程)
}
else{//如果还没有出现的新节点。把father设成他自己(表示根节点),height设成0
father[x]=x;
height[x]=0;
}
return father[x];
}
void Union(int a,int b){//合并函数
a=find(a);
b=find(b);
if(a!=b){
if(height[a]>height[b])
father[b]=a;
else if(height[b]>height[a])
father[a]=b;
else{
father[a]=b;
height[a]++;
}
}
}
int main()
{
int i,j;
while(cin>>i>>j){
//if(i==0)break;
Union(i,j);
}
int sum=0;
for(auto it=father.begin();it!=father.end();it++){
if(it->first==it->second)sum++; //只要有一个父亲是本身的就说明是根节点
}
cout<<sum<<endl;
return 0;
} #include <iostream>
#include<map>
using namespace std;
map<int, int>mp;
//map用来映射每个顶点对应的父节点是什么
int find(int x) {
//用于找到父节点以及路径压缩
if (x != mp[x])
mp[x] = find(mp[x]);
return mp[x];
}
void union_two(int A, int B) {
int c1 = find(A);
int c2 = find(B);
if (c1 != c2)
mp[c2] = c1; //若相连接的两个结点根结点不同,则合并两个根结点
}
int main() {
//这是简单的并查集的运用,因为序号不是连续的则用map映射来实现,表示存储对应的连接关系
int a, b;
while (cin >> a >> b) {
if (mp.find(a) ==mp.end()) { //若已有映射中无对应的结点则存入顶点信息,并将其根节点设为自己
mp[a] = a;
}
if (mp.find(b) ==mp.end()) {
mp[b] = b;
}
union_two(a, b);
}
int cnt = 0;
//处理完所有的信息之后,再判断联通分支数为多少,其为该顶点的编号与对应父节点的编号相同的顶点的数量
for (auto it : mp) {
if (it.first==it.second)
cnt++;
}
cout << cnt << endl;
return 0;
} #include<bits/stdc++.h>
using namespace std;
vector<int> adj[500000];
map<int,int> mp;
void dfs(int u){
mp[u]=1;
for(int i=0;i<adj[u].size();i++){
if(mp[adj[u][i]]==0){
dfs(adj[u][i]);
}
}
}
void dfsTravel(int& count){
for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
if(it->second==0){
dfs(it->first);
count++;
}
}
}
int main(){
int i,j;
//memset(visited,0,sizeof(visited));
while(cin>>i>>j){
adj[i].push_back(j);
adj[j].push_back(i);
mp[i]=mp[j]=0;
}
int count=0;
dfsTravel(count);
cout<<count<<endl;
return 0;
} DFS 染色,一次染一个联通集
#include <functional>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
int main() {
unordered_map<int, vector<int>> g;
unordered_set<int> st;
int a, b;
while (cin >> a >> b) {
st.insert(a);
st.insert(b);
if (a == b) continue;
g[a].push_back(b);
g[b].push_back(a);
}
unordered_map<int, bool> vis;
vector<int> nodes(st.begin(), st.end());
for (auto& [k, v]: g) vis[k] = false;
function<void(int, int)> dfs = [&](int cur, int pre) {
if (vis[cur] == true) return;
vis[cur] = true;
for (auto nxt: g[cur]) {
if (nxt != pre && !vis[nxt]) {
dfs(nxt, cur);
}
}
};
int ans = 0;
for (int & node : nodes) {
if (!vis[node]) {
dfs(node, -1);
ans++;
}
}
cout << ans;
}
#include <iostream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
int top[2000001], setRank[2000001]; //数据范围一定要够大,有点毒瘤了
set<int> nodeSet;
void init(int x) {
for(int i = 1; i <= x; i++) {
top[i] = i;
setRank[i] = 0;
}
}
//非递归写法,常数有所优化
int find(int x)
{
while(top[x] != x)
{
int t = x;
x = top[x];
top[t] = top[x];
}
return x;
}
void set_union(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
if(setRank[fx] > setRank[fy]) top[fy] = fx;
else if(setRank[fx] < setRank[fy]) top[fx] = fy;
else top[fy] = fx, setRank[fx] ++;
}
}
int main() {
int m, n;
int max_num = -1;
init(2000000);
while(cin >> m >> n) {
nodeSet.insert(m);
nodeSet.insert(n);
set_union(m, n);
}
int cnt = 0;
for(auto i : nodeSet) {
if(find(i) == i) cnt++;
}
cout << cnt << endl;
return 0;
} use std::io::{self, *};
fn main() {
println!("26202");
} #include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
vector<int> father(N, 0);
int find(int u){
return father[u] == -1 ? u : father[u] = find(father[u]);
}
void join(int u, int v){
u = find(u);
v = find(v);
if( u == v) return;
else father[v] = u;
}
int main() {
int u, v;
while(cin>>u>>v){
if(father[u] == 0) father[u] = -1;
if(father[v] == 0) father[v] = -1;
join(u, v);
}
int count = 0;
for(int i = 0; i < N; i++){
if(father[i] == -1) count++;
}
cout<<count<<endl;
} #include <cstdint>
#include <iostream>
#include<vector>
#include<map>
using namespace std;
map<int,int>node;
struct pairnode{
int first;
int second;
pairnode(int _first,int _second){
first=_first;
second=_second;
}
};
void Init(int visit[],int n){
for(int i=0;i<n;i++){
visit[i]=i;
}
}
int findfather(int visit[],int n){
if(visit[n]==n){
return n;
}
else return findfather(visit,visit[n]);
}
int main() {
vector<pairnode> v;
int a, b;
int i=0;
int u, w;
while (cin >> a >> b) {
if (node.count(a) == 0) {
node.insert({a,i++});
}
if (node.count(b) == 0) {
node.insert({b,i++});
}
pairnode p(a, b);
v.push_back(p);
}
int setnode = node.size();
int visit[setnode];
Init(visit,setnode);
for (i = 0; i < v.size(); i++) {
u = v[i].first;
w = v[i].second;
int uroot = findfather(visit,node[u]);
int wroot = findfather(visit,node[w]);
if (uroot != wroot) {
setnode--;
visit[wroot]=uroot;
}
}
cout << setnode << endl;
return 0;
} #include <iostream>
#include <cstdio>
#include <map>
using namespace std;
int parent[1000000];
map<int, int> ::iterator it;
void innital(int n, map<int, int>& nodes) {//nodes在主函数,注意传参
it = nodes.find(n);
if (it == nodes.end()) {
nodes[n] = 1;
parent[n] = -1;
}
}
int findroot(int x) {
while (parent[x] != -1) x = parent[x];
return x;
}
int unionset(int n1, int n2, int parent[1000000]) {
int n1_root, n2_root;
n1_root = findroot(n1);
n2_root = findroot(n2);
if (n1_root == n2_root) return 0; //同集合不用合并
else {
parent[n1_root] = n2_root;
return 1;
}
}
int main() {//统计入度为0的节点的数量。如果入度为0的节点数量大于1,则不满足树的定义。检查是否有环路存在。
int n1, n2;
int k = 0;
int flag = 1;
map<int, int> nodes;
map<int, int> degree;
while (cin >> n1 >> n2) {
innital(n1, nodes);
innital(n2, nodes);
unionset(n1, n2, parent); //集合合并,合并失败有环
}
int j = 0;
for (it = nodes.begin(); it != nodes.end(); it++) {
int n=it->first;
if (findroot(n)==n) j++;
}
cout<<j<<endl;
return 0;
}
import sys
nodes = set()
edges = []
for line in sys.stdin:
start, end = list(map(int, line.strip().split()))
nodes.add(start)
nodes.add(end)
edges.append([start, end])
edges.append([end, start])
nodes = list(nodes)
adjusts = {}
isvisited = {}
for node in nodes:
adjusts[node] = []
isvisited[node] = False
for start, end in edges:
if start == end:
pass
else:
adjusts[start].append(end)
count = 0
for node in nodes:
if not isvisited[node]:
count += 1
queue = [node]
while len(queue) > 0:
cur = queue[0]
queue.pop(0)
for next_node in adjusts[cur]:
if not isvisited[next_node]:
queue.append(next_node)
isvisited[next_node] = True
print(count)