#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; }
#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; }
//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; }
#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)
#include <iostream> #include <map> #include <set> #include <vector> using namespace std; set<int>vertices; //结点集 map<int, int>father; //每个结点的父亲结点 map<int, int>height; //每个结点的高度 //添加结点并初始化映射值 void Initial(int x) { if (vertices.find(x) == vertices.end()) { //判断结点是否已存在 vertices.insert(x); //向结点集中插入结点 father[x] = x; //每个结点的父亲为自己 height[x] = 0; //每个结点的高度为0 } } 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[y] < height[x]) { father[y] = x; } else { father[y] = x; height[x]++; } } } int main() { int a, b; while (cin >> a >> b) { Initial(a); //添加结点 Initial(b); //添加结点 Union(a, b); //合并集合 } int component = 0; //连通分量 for (const auto& i : vertices) { if (Find(i) == i) { //集合数目 component++; } } cout << component << endl; return 0; }
//求连通分量 即并查集的个数 #include <cstdio> int father[150000] = {0}; int flag[150000] = {0};//假设都未访问 int height[150000] = {0}; int Find(int x) { if (x != father[x]) father[x] = Find(father[x]); return father[x]; } int main() { int a, b; int num = 0; int max=0,min=0; while (scanf("%d %d", &a, &b) != EOF) { if (flag[a] == 0) { father[a] = a; height[a] = 1; flag[a] = 1; max=max>a?max:a; min=min<a?min:a; } if(a==b) continue; if (flag[b] == 0) { father[b] = b; height[b] = 1; flag[b] = 1; max=max>b?max:b; min=min<b?min:b; } a = Find(a); b = Find(b); //合并结点 如果根不同则加入其根节点 if (height[a] < height[b]){ father[a] = b; } else if (height[a] > height[b]){ father[b] = a; } else { father[b] = a; height[a]++; } } //求连通分量 for(int i=min;i<=max;i++){ if(father[i]==i&&flag[i]==1){ num++; } } printf("%d\n",num); }第二种比较好理解的map 省空间易于理解 但是更慢了 294ms 12232KB
#include <stdio.h> #include <map> using namespace std; map<int,int> father;//map保存信息 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[x]=x; height[x]=1; } return father[x]; } void Union(int x, int y) { //合并两棵树 x = Find(x); y = Find(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() { int i, j; while (scanf("%d%d", &i, &j) != EOF) { Union(i,j); } int num=0; for(map<int,int>::iterator it=father.begin();it!=father.end();it++){ if(it->first==it->second) num++; } printf("%d\n",num); }
#include <cstdio> #define maxn 1000000 int father[maxn]; int flag[maxn]; void init() { for (int i = 1; i <= maxn; i++) { father[i] = i; } } int findFather(int x) { while (x != father[x]) x = father[x]; return x; } void Union(int a, int b) { int fa = findFather(a); int fb = findFather(b); if (fa != fb) father[fb] = fa; } int main() { int x, y, cnt = 0; init(); while (scanf("%d %d", &x, &y) != EOF) { Union(x, y); flag[x] = flag[y] = 1; } for (int i = 1; i <= maxn; i++) { if (i == father[i] && flag[i] == 1) cnt++; } printf("%d\n", cnt); return 0; }
//求连通分支数即是求出连通分量 #include <cstdio> #include <iostream> #include <map> using namespace std; const int MAXIN=1000000; int father[MAXIN]; int height[MAXIN]; bool visit[MAXIN]; void getbe(){ for(int i=1;i<MAXIN;i++){ father[i]=i; height[i]=0; visit[i]=false; } } int find(int x){ while(x!=father[x]){ x=father[x]; } return x; } void unions(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[x]=y; height[y]++; } } } int main(){ int x,y; getbe(); while(scanf("%d %d",&x,&y)!=EOF){ unions(x,y); visit[x]=true; visit[y]=true; } int ans=0; for(int i=1;i<MAXIN;i++){ if(!visit[i]){ continue; } if(father[i]==i){ ans++; } } cout<<ans<<endl; return 0; }