一、连通分量
无向图 G 有 n 个顶点和 m 条边。求 G 的连通分量的数目。
输入格式:
第1行,2个整数n和m,用空格分隔,分别表示顶点数和边数, 1≤n≤50000, 1≤m≤100000.
第2到m+1行,每行两个整数u和v,用空格分隔,表示顶点u到顶点v有一条边,u和v是顶点编号,1≤u,v≤n.
输出格式:
1行,1个整数,表示所求连通分量的数目。
输入样例:
在这里给出一组输入。例如:
6 5
1 3
1 2
2 3
4 5
5 6
输出样例:
在这里给出相应的输出。例如:
2
【解题思路】:
我们可以从输入下手,输入是加边,也就是在输入的两个点之间建立联系,而不同联通分量之间是不能访问的,这点就很像我们平常说的关系网,因此我最先想到用并查集去求解。我的代码使用了路径压缩。
#include<iostream>
#include<algorithm>
#define maxsize 100000
using namespace std;
int father[maxsize];
void make_set(int x){ //这部分是并查集的实现
father[x]=0;
}
int find(int x){
if(father[x]<=0) return x;
int fx=find(father[x]);
father[x]=fx;
return fx;
}
void Union(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy) return;
if(father[fx]<father[fy]) father[fy]=fx;
else{
if(father[fx]==father[fy]) father[fy]--;
father[fx]=fy;
}
}
int main(){
int i,n,m;
int v1,v2,tmp,cnt[maxsize],top=0;
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++){
make_set(i);
}
for(i=1;i<=m;i++){
scanf("%d %d",&v1,&v2);
Union(v1,v2);
}
for(i=1;i<=n;i++){
cnt[top++]=find(i);
}
sort(cnt,cnt+n); //对所有的点所在的联通分量的代表院排序
tmp=cnt[0];top=1;
for(i=1;i<n;i++){
if(cnt[i]!=tmp){
tmp=cnt[i];
top++; //遇到前后代表元不同时就计数加一
}
}
cout<<top<<endl;
}
二、整数拆分
整数拆分是一个古老又有趣的问题。请给出将正整数 n 拆分成 k 个正整数的所有不重复方案。例如,将 5 拆分成 2 个正整数的不重复方案,有如下2组:(1,4)和(2,3)。注意(1,4) 和(4,1)被视为同一方案。每种方案按递增序输出,所有方案按方案递增序输出。
输入格式:
1行,2个整数n和k,用空格分隔, 1≤k≤n≤50.
输出格式:
若干行,每行一个拆分方案,方案中的数用空格分隔。
最后一行,给出不同拆分方案的总数。
输入样例:
在这里给出一组输入。例如:
5 2
输出样例:
在这里给出相应的输出。例如:
1