数据结构第四次实验题解

 

 

一、连通分量 

无向图 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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值