分治算法:集合划分问题

数学概念

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。即一种分目标完成程序算法,简单问题可用二分法完成。

分治法解题的一般步骤

(1)分解,将要解决的问题划分成若干规模较小的同类问题;

(2)求解,当子问题划分得足够小时,用较简单的方法解决;

(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

问题实例:集合划分问题

n 个元素的集合{1,2,..., n }可以划分为若干个非空子集。例如,当 n=4 时,集合{1,2, 3,4}可以划分为 15 个不同的非空子集如下:
{{1},{2},{3},{4}},
{{1,2},{3},{4}},
{{1,3},{2},{4}},
{{1,4},{2},{3}},
{{2,3},{1},{4}},
{{2,4},{1},{3}},
{{3,4},{1},{2}},
{{1,2},{3,4}},
{{1,3},{2,4}},
{{1,4},{2,3}},
{{1,2,3},{4}},
{{1,2,4},{3}},
{{1,3,4},{2}},
{{2,3,4},{1}},
{{1,2,3,4}}
其中,集合{{1,2,3,4}}由 1 个子集组成;集合{{1,2},{3,4}},{{1,3},{2, 4}},{{1,4},{2,3}},{{1,2,3},{4}},{{1,2,4},{3}},{{1,3,4},{2}},{{2, 3,4},{1}}由 2 个子集组成;集合{{1,2},{3},{4}},{{1,3},{2},{4}},{{1,4}, {2},{3}},{{2,3},{1},{4}},{{2,4},{1},{3}},{{3,4},{1},{2}}由 3 个子集组成;集合{{1},{2},{3},{4}}由 4 个子集组成。
算法设计:给定正整数 n 和 m,计算出 n 个元素的集合{1,2,..., n }可以划分为多少个不同的由 m 个非空子集组成的集合。

数据输入
由文件 input.txt 提供输入数据。文件的第 1 行是元素个数 n 和非空子集数 m。

结果输出:

程序运行结束时,将计算出的不同的由m个非空子集组成的集合数输出到文件output.txt
中。

input.txt     output.txt 
4 3 		  6

问题分析

简单分析

①当n=m时,集合数为1

②当m=1时,集合数为1

复杂分析

①把前n-1个数分成m-1份,最后第n个数插进去。F(n-1,m-1)

②把前n-1个数分成m份,最后第n个数随便插到m个集合里的某个集合中。m*F(n-1,m)

F(n,m)=F(n-1,m-1)+m*F(n-1,m)

举例说明

1、当有3个数时

一个子集:{1,2,3} 共1个集合

两个子集:{{1,2}{3}、{{1,3}{2}、{{2,3}{1}} 共3个集合

三个子集:{{1}{2}{3}} 共1个集合

以两个子集为例(F(3,2))

①把前2个数分成1份({1,2}),最后第3个数插进去({3})

②把前2个数分成2份({1}、{2}),最后第3个数随便插到2个集合里的某个集合中,如:{1,3}{2}或{1}{2,3},两个集合两种插法,三个集合三种插法

2、当有4个数时

一个子集:{{1,2,3,4}},F(4,1)=1;
两个子集:{{1,2,3},{4}},{{1,2,4},{3}},{{1,2},{3,4}},{{1,3,4},{2}},{{1,3},{2,4}},{{2,3,4},{1}},{{2,3},{1,4}},
     F(4,2)=F(3,1)+2F(3,2)=7
三个子集:{{1,2},{3},{4}},{{1,3},{2},{4}},{{2,3},{1},{4}},{{1,4},{2},{3}},{{1},{2,4},{3}},{{1},{2},{3,4}},
     F(4,3)=F(3,2)+3F(3,3)=6
四个子集:{{1},{2},{3},{4}},F(4,4)=1。
 

#include<stdio.h>
#include<stdlib.h>
int part(int n,int m){
	if(m==n||m==1){
		return 1;
	}
	else if(m>n||m==0){
		return 0;
	}
	else{
		return part(n-1,m-1)+m*part(n-1,m);
	}
}
void main(){
//	int n,m;
//	scanf("%d %d",&n,&m);//n为集合元素个数,m为子集个数 
//	printf("%d\n",part(n,m));
//	return 0;

 int n,m,c;
	FILE *fp,*fp1;
	if ((fp = fopen("input.txt", "r")) == NULL) {
		printf("文件错误\n");
		exit(0);
	}
    fscanf(fp, "%d %d", &n,&m); //从文件中读取
	fclose(fp);

    c = part(n, m);
	if ((fp1 = fopen("output.txt", "w")) == NULL) 
	{
		printf("文件错误\n");
		exit(0);
	}
    fprintf(fp1, "%d", c);//写入文件
	fclose(fp1);
    return 0;

}

 其他问题:给定正整数 n ,计算出 n 个元素的集合{1,2,..., n }可以划分为多少个非空子集。

#include<stdio.h>
#include<stdlib.h>
int part(int n,int m){
	if(m==n||m==1){
		return 1;
	}
	else if(m>n||m==0){
		return 0;
	}
	else{
		return part(n-1,m-1)+m*part(n-1,m);
	}
}
void main(){

 int n,m;
 int sum=0;
	FILE *fp,*fp1;
	if ((fp = fopen("input.txt", "r")) == NULL) {
		printf("文件错误\n");
		exit(0);
	}
    fscanf(fp, "%d %d", &n,&m); //从文件中读取
	fclose(fp);
	 
	 for(int i=1;i<=n;i++){
	 	sum+=part(n,i);
	 }
   
	if ((fp1 = fopen("output.txt", "w")) == NULL) 
	{
		printf("文件错误\n");
		exit(0);
	}
    fprintf(fp1, "%d", sum);//写入文件
	fclose(fp1);
    return 0;

}

  • 27
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值