每组数据的第一行是两个整数 n 和 m(0<=n<=1000)。n 表示图的顶点数目,m 表示图中边的数目。随后有 m 行数据,每行有两个值 x 和 y(0<x, y <=n),表示顶点 x 和 y 相连,顶点的编号从 1 开始计算。输入不保证这些边是否重复。
对于每组输入数据,如果所有顶点都是连通的,输出"YES",否则输出"NO"。
4 3 1 2 2 3 3 2 3 2 1 2 2 3 0 0
NO YES
#include <string.h>
#include <stdio.h>
int findroot( int number, int JH[])
{
if (JH[number]==-1) return number;
else
{
int temp= findroot (JH[number], JH);
JH[number]=temp;
return temp;
}
}
int main( int argc, const char * argv[]) {
int n,m;
while ( scanf ( "%d %d" ,&n,&m)!= EOF ) {
if (n==0)
break ;
int JH[1001];
int i;
for (i=1; i<=n; i++) {
JH[i]=-1;
}
for (i=1;i<=m;i++)
{
int temp,temp2;
scanf ( "%d" ,&temp);
scanf ( "%d" ,&temp2);
int root1= findroot (temp,JH);
int root2= findroot (temp2,JH);
if (root1!=root2)
{
JH[root2]=root1;
}
}
int count=0;
for (i=1; i<=n; i++) {
if (JH[i]==-1)
count++;
}
if (count>1)
printf ( "NO\n" );
else
printf ( "YES\n" );
}
return 0;
}
/*使用广度优先遍历判断是否为连通图*/ #include<cstdio> #include<iostream> #include<queue> #define MAXN 1001 using namespace std; queue<int> Q; bool G[MAXN][MAXN], visit[MAXN]; void Initial(int n){ /*初始化*/ for(int i=1;i<n+1;i++){ visit[i]=false; for(int j=1;j<n+1;j++) G[i][j] = false; } return ; } void BFS(int n){ Q.push(1); while(!Q.empty()){ int i=Q.front(); Q.pop(); visit[i]=true; for(int j=1;j<n+1;j++){ if(G[i][j] && !visit[j]) Q.push(j); } } return ; } int main(){ int n,m,x,y; while(cin>>n>>m){ if(!n && !m) break; Initial(n); while(m--){ cin>>x>>y; G[x][y]=true; G[y][x]=true; } BFS(n); bool connected=true; for(int i=1;i<n+1;i++){ if(!visit[i]){ connected=false; break; } } if(connected) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
//和浙江大学的畅通问题类似,又默写了一边,嘻嘻 #include<iostream> using namespace std; int father[1000]; int height[1000]; void Initial(int n){ for(int i=1; i<=n; i++){ father[i] = i; height[i] = 0; } return; } 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[y] = x; } else if(height[x]<height[y]){ father[x] = y; } else{ father[x] = y; height[y]++; } } return; } int main(){ int n,m; while(cin>>n){ Initial(n); cin>>m; if(n==0&&m==0){ break; } for(int i=0; i<m; i++){ int a,b; cin>>a>>b; Union(a,b); } int answer = -1; for(int i=1; i<=n; i++){ if(i==Find(i)){ answer++; } } if(answer==0){ cout<<"YES"<<endl; } else{ cout<<"NO"<<endl; } } return 0; }
//将每个元素看为一个集合,然后通过并查集合并集合,然后再将余下的集合连接起来即可 #include<bits/stdc++.h> using namespace std; int main(){ int n,m; while(cin>>n>>m&&n!=0&&m!=0){ int t=n-1; //3个城市只要2个道路即连通 int v[1000]; //保存连通的一个有效点 memset(v,-1,sizeof(v)); while(m--){ int x,y; cin>>x>>y; int a=x,b=y; while(v[a]!=-1)a=v[a];//找代表元素 while(v[b]!=-1)b=v[b]; if(a==b)continue; //该路无效,已存在有效路径 else v[b]=x,t-=1;//合并集合,需要路径-1 } if(t==0) cout<<"YES"<<endl; else cout<<"NO"<<endl; memset(v,-1,sizeof(v)); } return 0; }
/* *用并查集表征连通分量。两者在直观上是不同的,但是性质是相同的。 */ #include<bits/stdc++.h> using namespace std; const int maxn = 1e3; int father[maxn+5]; int n, m; void Initial() { for(int i = 1;i <= n; 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); while(cin >> n >> m && n && m) { Initial(); int u, v; for(int i = 0;i < m; i++) { cin >> u >> v; Union(u, v); } int ans = 0; for(int i = 1;i <= n; i++) ans += father[i] == i ? 1 : 0; if(ans == 1) cout << "YES" << '\n'; else cout << "NO" << '\n'; } return 0; }
package nowcoder02.demo49; import java.util.HashSet; import java.util.Scanner; public class Main { public static class UnionFind { private int[] id; public UnionFind(int N) { id = new int[N]; for(int i = 0; i < N; i++) id[i] = i; } public int find(int p) { return id[p]; } public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; for(int i = 0; i < id.length; i++) if(id[i] == pRoot) id[i] = qRoot; } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ int vertex = scanner.nextInt(); int edge = scanner.nextInt(); UnionFind union = new UnionFind(vertex + 1); for (int i = 0; i < edge; i++) union.union(scanner.nextInt(),scanner.nextInt()); HashSet<Integer> set = new HashSet<>(); for (int i = 0; i < vertex; i++) set.add(union.find(i+1)); System.out.println(set.size()==1?"YES":"NO"); } } }
#include<stdio.h> #define N 1001 int point[N]; int find(int x){ return x==point[x]? x:point[x]=find(point[x]); } int main(){ int m,n,x,y,u,v,count; for(int i=1;i<N;i++) point[i]=i; while(scanf("%d%d",&n,&m)!=EOF){ count=0; for(int i=0;i<m;i++){ scanf("%d%d",&x,&y); u=find(x);v=find(y); if(u!=v) point[y]=u; } for(int i=1;i<=n;i++){ if(point[i]==i) count++; } if(count==1) printf("YES\n"); else printf("NO\n"); } return 0; }
并查集 import java.util.Scanner; public class Main { static int[] root; public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()){ int n = in.nextInt(); int m = in.nextInt(); root = new int[n+1]; for(int i=0;i<=n;i++) root[i] = -1; for(int i=0;i<m;i++){ int x = in.nextInt(); int y = in.nextInt(); int a = findRoot(x); int b = findRoot(y); if(a!=b) root[a] = b; } int cnt=0; for(int i=1;i<=n;i++) if(root[i]==-1) cnt++; if(cnt==1) System.out.println("YES"); else System.out.println("NO"); } } public static int findRoot(int x){ if(root[x]==-1) return x; int tmp = findRoot(root[x]); root[x] = tmp; return tmp; } }
并查集 import java.util.Scanner; public class 连通分量 { private static int[] father; private static int n; public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()){ n = sc.nextInt(); if(n==0) break; int m = sc.nextInt(); father = new int[n+1]; for (int i = 1; i <= n; i++) { father[i] = i; } for(int i = 0;i<m ;i++){ int a = sc.nextInt(); int b = sc.nextInt(); union(a,b); } if(n<2) System.out.println("YES"); else System.out.println("NO"); } } private static void union(int a, int b) { int a_root = findfather(a); int b_root = findfather(b); if(a_root!=b_root){ father[a_root] = b_root; n--; } } private static int findfather(int a) { while(father[a] != a) a = father[a]; return a; } }
#include <stdio.h> #define N 1001 void Visit(bool G[N][N], bool visit[N], int n, int x) { visit[x]=true;//先访问1 for(int i=1; i<=n; i++) { if(G[i][x]==true&&visit[i]==false) Visit(G, visit, n, i); } } int main() { bool G[N][N];//用邻接矩阵存储这个图 bool visit[N]; int n, m, x, y; while(scanf("%d %d", &n, &m)!=EOF) { for(int i=1; i<=n; i++)//初始化 { visit[i]=false; for(int j=1; j<=n; j++) { G[i][j]=false; } } while(m--) { scanf("%d %d", &x, &y); G[x][y]=true; G[y][x]=true; } Visit(G, visit, n, 1); bool connected=true; for(int i=1; i<=n; i++) { if(!visit[i]) connected=false; } if(connected) printf("YES\n"); else printf("NO\n"); } return 0; }
#include<stdio.h> #define N 1001 int FindRoot(int Tree[],int x){ if(Tree[x]==-1) return x; else{ Tree[x]=FindRoot(Tree,Tree[x]); return Tree[x]; } } int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ int Tree[N]; int i,a,b; for(i=1;i<=n;i++) Tree[i]=-1; while(m--){ scanf("%d%d",&a,&b); a=FindRoot(Tree,a); b=FindRoot(Tree,b); if(a!=b) Tree[b]=a; } int ans=0; for(i=1;i<=n;i++) if(Tree[i]==-1) ans++; puts(ans>1?"NO":"YES"); } }
#include <cstdio> #include <iostream> using namespace std; const int MAXN = 1000+10; int father[MAXN]; int height[MAXN]; void Init(int n); int Find(int x); void Union(int x, int y); // 连通图 ——运用并查集判断是否为连通图 int main() { int n, m; while (scanf("%d %d", &n, &m) != EOF) { if (n == 0 && m == 0) { break; } // 初始化father Init(n); for (int i = 1; i <= m; i++) { int x, y; scanf("%d %d", &x, &y); Union(x, y); } int answer = 0;// 若连通,所有节点的Find值都 == t for (int i = 1; i <= n; i++) { if (Find(i) == i) {// 存在不止一颗树 answer++; } } if (answer == 1) { cout << "YES" << endl; }else { cout << "NO" << endl; } } return 0; } // 初始化并查集 void Init(int n) { for (int i = 1; i <= n; i++) {// 注意小于等于n!并且从1开始 father[i] = i; height[i] = 0; } return; } // 寻找父节点 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]++;// 树高++ } } return; }
#include <iostream> #include<vector> using namespace std; void dfs(vector< vector<int> >&graph,int i,vector<bool>& v){ v[i] = true; for(int j=0;j<graph[i].size();j++){ if(graph[i][j]==1&&!v[j]) dfs(graph,j,v); } } int main() { int n,m; while(cin>>n>>m&&m*n!=0){ vector< vector<int> > g(n,vector<int>(n,0)); vector<bool> visit(n,false); for(int i=0;i<n;i++) g[i][i] = 1; while(m--){ int a,b; cin>>a>>b; g[a-1][b-1] = 1; g[b-1][a-1] = 1; } int result = 0; for(int i =0;i<n;i++){ if(!visit[i]){ dfs(g,i,visit); result++; } } result==1?cout<<"YES"<<endl:cout<<"NO"<<endl; } return 0; }
#include<stdio.h> int father[2000]; void init(int n){ for(int i=0;i<=n;i++){ father[i] = i; } } int FindFather(int n){ if(father[n]==n) return n; else{ father[n] = FindFather(father[n]); return father[n]; } } void unoin(int a,int b){ int r1 = FindFather(a); int r2 = FindFather(b); father[r2] = r1; } int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ int edge = 0; init(n); if(n==0&&m==0) break; else{ for(int i=0;i<m;i++){ int a,b; scanf("%d%d",&a,&b); int r1 = FindFather(a); int r2 = FindFather(b); if(r1!=r2){ father[r1] = r2; edge++; } } } if(edge+1==n) printf("YES\n"); else printf("NO\n"); } }
#include <iostream> #include <vector> using namespace std; const int MAXN = 1000; vector<int>father(MAXN); //父亲结点 vector<int>height(MAXN); //结点高度 void Initial(int n) { //初始化 for (int i = 0; i <= n; i++) { father[i] = i; //每个结点的父亲为自己 height[i] = 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 n, m; while (cin >> n >> m) { Initial(n); //初始化 while (m--) { int x, y; cin >> x >> y; Union(x, y); //合并集合 } int component = 0; //连通分量 for (int i = 1; i <= n; i++) { if (Find(i) == i) { //集合数目 component++; } } cout << (component == 1 ? "YES" : "NO") << endl; } return 0; }
#include "bits/stdc++.h" using namespace std; int n, m; const int maxn = 1001; int father[maxn]; int height[maxn] = {0}; //这里把height初始化为0即可,后面并操作时再修改 void initial() { for (int i = 0; i <= n; i++) { father[i] = i; // 先默认设置为自身即可 } return; } int find(int x) { while (x != father[x]) { x = father[x]; } return x; } void Union(int x, int y) { //union 是默认关键字,应该避免使用 int f_a = find(x); int f_b = find(y); if (f_a != f_b) { if (height[f_a] > height[f_b]) { father[f_b] = f_a; } else if (height[f_a] < height[f_b]) { father[f_a] = f_b; } else { father[f_a] = f_b; height[f_b]++; } } } int main() { while (scanf("%d %d" , &n,&m)!=EOF) { if(n==0 && m==0) break; initial(); for (int i = 0; i < m; i++) { int temp1, temp2; scanf("%d %d", &temp1, &temp2); Union(temp1, temp2); } int res = 0; for (int i = 1; i <= n; i++) { if (i == father[i]) { res++; } } if (res == 1) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
#include<cstdio> #define N 1000 using namespace std; int father[N]; int height[N]; void Init(int n){ for (int i = 1; i <= n; i++) { father[i] = i; height[i] = 1; } } int Find(int x){ if(x!=father[x]){ father[x] = Find(father[x]); } return father[x]; } void Union(int x, int y,int &num){ x = Find(x); y = Find(y); if (x != y) { --num; } 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 m, n; while(scanf("%d%d",&n,&m)!=EOF) { if (m == 0 && n == 0) { break; } Init(n); int num = n; for (int i = 0; i < m; ++i) { int x, y; scanf("%d%d", &x, &y); Union(x, y,num); } if (num == 1) { printf("YES\n"); } else{ printf("NO\n"); } } }
#include<stdio.h> int father[2000]; void Init(int n){ //初始化,令所有节点的祖先是自己 for(int i=1;i<=n;i++){ father[i]=i; } } int Find(int x){ //查找节点x的祖先 if(x==father[x]){ //x就是树根 return father[x]; } else{ return Find(father[x]);//递归寻找x的祖先 } } void Union(int x,int y,int &num){ //合并并查集 x=Find(x); y=Find(y); if(x==y){ //x与y在一个集合当中 return; } else{ //x与y不在一个集合,合并两个集合 //令y的祖先是x father[y]=x; num--; } } int main(){ int n,m;//n个节点,m条边 while(scanf("%d%d",&n,&m)!=EOF){ if(n==0&&m==0){ break; } Init(n); int num=n;//初始状态n个并查集 for(int i=0;i<m;i++){ int x,y; scanf("%d%d",&x,&y); Union(x,y,num); } if(1==num){ printf("YES\n"); } else{ printf("NO\n"); } } }
数组实现的并查集应该算很初级的算法 #include <iostream> #include <vector> using namespace std; vector<int> parent; int find(int a){ if(parent[a]==-2){ parent[a] = -1; return a; } if(parent[a] == -1) return a; if(parent[a]!=-1) return find(parent[a]); return a; } void to_union(int a,int b){ int x = find(a-1); int y = find(b-1); if(y!=x){ parent[b-1] = x; } } int main() { int a, b; while (cin >> a >> b) { // 注意 while 处理多个 case parent.resize(a,-2); for(int i =0; i < b;++i){ int x,y; cin >> x >>y; to_union(x,y); } int count = 0; for(int i=0; i < a;++i){ if(parent[i]==-1||parent[i]==-2) count++; } if(count ==1) cout <<"YES" << endl; else cout <<"NO" << endl; } } // 64 位输出请用 printf("%lld")