数学概念
分治算法的基本思想是将一个规模为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;
}