K - How Many Tables
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
InputThe input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
OutputFor each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
Sample Input
2 5 3 1 2 2 3 4 5 5 1 2 5
Sample Output
2 4
这个题目非常明显用并查集做!!!
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=1010; int f[maxn]; bool vis[maxn]; void init(int n) { for(int i=1;i<=n;i++) f[i]=i; } int fi(int x) { return f[x]==x? x: f[x]=fi(f[x]); } void unit(int a,int b) { int t1=fi(a); int t2=fi(b); if(t1==t2) return ; f[t1]=t2; } int main() { int t; scanf("%d",&t); while(t--) { int n,m,cnt=0; memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&m); init(n); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); unit(a,b); } for(int i=1;i<=n;i++) f[i]=fi(i); for(int i=1;i<=n;i++) { if(vis[f[i]]) continue; // printf("aa %d ",f[i]); vis[f[i]]=1; cnt++; } printf("%d ",cnt); } }
L - 畅通工程
Input测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。
注意:两个城市之间可以有多条道路相通,也就是说
3 3
1 2
1 2
2 1
这种输入也是合法的
当N为0时,输入结束,该用例不被处理。
Output对每个测试用例,在1行里输出最少还需要建设的道路数目。
Sample Input
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
Sample Output
1 0 2 998 Huge input, scanf is recommended.
Hint
Hint
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=1010; int f[maxn],high[maxn]; void init(int n) { for(int i=1;i<=n;i++) f[i]=i; } int findd(int x) { return f[x]==x? x : f[x]=findd(f[x]); } void unionn(int a,int b) { int t1=findd(a); int t2=findd(b); if(t1==t2) return ; if(high[t2]>high[t1]) f[t1]=t2; else { f[t2]=t1; if(high[t1]==high[t2]) high[t1]++; } } int main() { int n,m; while(1) { memset(high,0,sizeof(high)); scanf("%d",&n); if(n==0) break; scanf("%d",&m); if(m==0) { printf("%d ",n-1); continue; } if(n==1) { printf("0 "); continue; } init(n); int a,b,cnt=0; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); unionn(a,b); } for(int i=1;i<=n;i++) { if(f[i]==i) cnt++; } printf("%d ",cnt-1); } return 0; }
并查集其实很简单,学一下应该就可以学会了,接下来推荐一篇博文,写的很好,还有一个大佬的视频,这个是最基础的,当然除此之外,还有种类并查集和带权并查集。
博文:https://blog.csdn.net/Hacker_ZhiDian/article/details/60965556