分治算法例题
分治法解决问题的步骤

分治法解决问题的步骤一、基础概念类题目(1 - 5题)题目1:简述分治法解决问题的基本步骤。
解析:分治法解决问题主要有三个步骤:1. 分解(Divide):将原问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题。
例如,对于排序问题,可将一个大的数组分成两个较小的子数组。
2. 求解(Conquer):递归地求解这些子问题。
如果子问题规模足够小,则直接求解(通常是一些简单的基础情况)。
对于小到只有一个元素的子数组,它本身就是有序的。
3. 合并(Combine):将各个子问题的解合并为原问题的解。
在排序中,将两个已排序的子数组合并成一个大的有序数组。
题目2:在分治法中,分解原问题时需要遵循哪些原则?解析:1. 子问题规模更小:分解后的子问题规模要比原问题小,这样才能逐步简化问题。
例如在归并排序中,不断将数组对半分,子数组的长度不断减小。
2. 子问题相互独立:子问题之间应该尽量没有相互依赖关系。
以矩阵乘法的分治算法为例,划分后的子矩阵乘法之间相互独立进行计算。
3. 子问题与原问题形式相同:方便递归求解。
如二分查找中,每次查找的子区间仍然是一个有序区间,和原始的有序区间查找问题形式相同。
题目3:分治法中的“求解”步骤,如果子问题规模小到什么程度可以直接求解?解析:当子问题规模小到可以用简单的、直接的方法(如常量时间或线性时间复杂度的方法)解决时,就可以直接求解。
例如,在求数组中的最大最小值问题中,当子数组只有一个元素时,这个元素既是最大值也是最小值,可以直接得出结果。
题目4:分治法的“合并”步骤有什么重要性?解析:1. 构建完整解:它将各个子问题的解组合起来形成原问题的解。
例如在归并排序中,单独的两个子数组排序好后,只有通过合并操作才能得到整个数组的有序排列。
2. 保证算法正确性:如果合并步骤不正确,即使子问题求解正确,也无法得到原问题的正确答案。
例如在分治算法计算斐波那契数列时,合并不同子问题的结果来得到正确的斐波那契数是很关键的。
分治算法-残缺棋盘

分治算法-残缺棋盘残缺棋盘是⼀个2^k*2^个⽅格的棋盘,其中恰有1个⽅格残缺。
图中给出,其中残缺部分⽤阴影表⽰。
这样的棋盘称为"三格板",残缺棋盘问题就是⽤这四种三格板覆盖更⼤的残缺棋盘。
再次覆盖中要求:(1)两个三格板不能重复。
(2)三格板不能覆盖残缺棋盘⽅格,但必须覆盖到其他所有的⽅格。
算法思路:利⽤分治算法将棋盘细化,逐步解决,以4*4为例⾸先判断残缺的位置在哪⾥,然后在中间填上对应的三格板,如在上图中间拼上三⾓板(4),变成下⾯这样然后通过中间将其分成了4个2*2的⼩残缺棋盘,从⽽问题得以解决4*4的分析过于简单,现在我们以8*8为例进⾏分析,能更清楚的理解这个例⼦中分治算法的思想⾸先将三格板放置在中间,将其分4个⼩的4*4的残缺棋盘通过红⾊线将其划分成4个4*4的残缺棋盘,现在以左上的残缺棋盘为例然后将左的4*4的⼩棋盘右划分成了4个2*2的⼩棋盘,这样就将问题优化成了2*2的三⾓棋盘的⼩问题,这样很快就能将左上的4*4的残缺棋盘解决了下⾯继续分析右上的4*4的棋盘,根据残缺的⽅格在⼩棋盘中的位置,在中间选择合适的三格板将⼩的残缺棋盘继续划分,将问题分化成更⼩的状态接着的问题和上⾯⼀样分析。
右上⾓的⼩棋盘很快也能解决了,下⾯两块残缺棋盘的分析⽅法和上⾯的⼀样,整个问题就这样⼀步步的分解成⼩问题,然后解决了。
下⾯是源代码#include <iostream>using namespace std;int amount,Board[100][100];void Cover(int tr,int tc,int dr,int dc,int size){int s,t;if(size<2)return ;amount++;t=amount;s=size/2;if(dr<tr+s&&dc<tc+s)//残缺在左上⾓{//覆盖中间位置Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s-1]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,dr,dc,s);//覆盖左上Cover(tr,tc+s,tr+s-1,tc+s,s);//覆盖右上Cover(tr+s,tc,tr+s,tc+s-1,s);//覆盖左下Cover(tr+s,tc+s,tr+s,tc+s,s);//覆盖右下}else if(dr<tr+s&&dc>=tc+s)//残缺在右上⾓{Board[tr+s-1][tc+s-1]=t;Board[tr+s][tc+s-1]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,dr,dc,s);Cover(tr+s,tc,tr+s,tc+s-1,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}else if(dr>=tr+s&&dc<tc+s)//残缺在左下 {Board[tr+s-1][tc+s-1]=t;Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc,dr,dc,s);Cover(tr+s,tc+s,tr+s,tc+s,s);}else{Board[tr+s-1][tc+s-1]=t;Board[tr+s-1][tc+s]=t;Board[tr+s][tc+s-1]=t;Cover(tr,tc,tr+s-1,tc+s-1,s);Cover(tr,tc+s,tr+s-1,tc+s,s);Cover(tr+s,tc,tr+s,tc+s-1,s);Cover(tr+s,tc+s,dr,dc,s);}}void Print(int s){for(int i=1;i<=s;i++){for(int j=1;j<=s;j++)printf("%5d ",Board[i][j]);printf("\n");}}int main(){int s=1,k,x,y;printf("输⼊2残缺棋盘的规模:2^k,k="); scanf("%d",&k);for(int i=1;i<=k;i++)s*=2;printf("输⼊棋盘残缺位置(x,y):");scanf("%d%d",&x,&y);Board[x][y]=0;Cover(1,1,x,y,s);Print(s);return 0;}。
十、用分治法求金块问题: 老板有一袋金块(共n块,n是2的

十、用分治法求金块问题:老板有一袋金块(共n块,n是2的幂(n>=2)),最优秀的雇员得到其中最重的一块,最差的雇员得到其中最轻的一块。
假设有一台比较重量的仪器,我们希望用最少的比较次数找出最重的金块(书P130).#include<iostream.h>int n;float a[100];maxmin(int i,int j,float &fmax,float &fmin) {int mid;float lmax,lmin,rmax,rmin;if(i==j){fmax=a[i];fmin=a[i];}else if(i==j-1){if(a[i]<a[j]){fmax=a[j];fmin=a[i];}else{fmax=a[i];fmin=a[j];}}else{mid=(i+j)/2;maxmin(i,mid,lmax,lmin);maxmin(mid+1,j,rmax,rmin);if(lmax>rmax)fmax=lmax;elsefmax=rmax;if(lmin>rmin)fmin=rmin;elsefmin=lmin;}}void main(){float fmax=0;float fmin=0;cout<<"请输入一维数组的长度"<<endl;cin>>n;cout<<"请初始化数组!"<<endl;for(int i=0;i<n;i++)cin>>a[i];maxmin(0,n-1,fmax,fmin);cout<<"fmax="<<fmax<<endl;cout<<"fmin="<<fmin<<endl;}十七、数塔问题:如图所示的一个数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一直走到底层,要求找出一条路径,使路径上的数值和最大(书P157).。
dda算法画直线例题

dda算法画直线例题dda算法是一种常用于计算机图形学中的算法,用于在计算机中绘制直线或其他几何形状。
本例题将通过dda算法绘制一条直线,帮助读者了解该算法的基本原理和应用。
一、算法概述dda算法是一种分治算法,它将原始的直线绘制问题分解为更小的子问题,逐个解决这些子问题,最终得到完整的绘制结果。
该算法的核心思想是通过逐点地更新像素位置,逐步逼近目标位置,从而实现直线的绘制。
二、实现步骤1.初始化:设置绘图窗口大小,确定要绘制的直线起点和终点。
2.循环迭代:对于每个像素点,按照dda算法的步骤进行更新。
具体步骤如下:a.计算当前像素点到直线起点的距离(dx),并将其与偏移量(delta)比较。
b.如果dx小于或等于delta,则当前像素点已经在直线上,无需进一步更新。
c.否则,根据dda算法的公式计算新的像素位置(new_x),并将其与当前像素位置进行比较。
d.如果new_x小于或等于当前像素位置,则将当前像素位置更新为new_x;否则,继续迭代下一个像素点。
3.重复步骤2直到绘制完整个窗口。
三、代码实现以下是一个简单的代码实现,使用c语言描述dda算法绘制直线的过程:```c#include<stdio.h>#include<stdlib.h>#include<math.h>#defineWIDTH800//绘图窗口宽度#defineHEIGHT600//绘图窗口高度voiddraw_line(intstart_x,intstart_y,intend_x,intend_y){inti,j,dx,dy,delta,new_x,new_y;for(i=0;i<HEIGHT;i++){for(j=0;j<WIDTH;j++){dx=end_x-start_x;dy=end_y-start_y;delta=sqrt(dx*dx+dy*dy);//计算偏移量if(dx<=delta||j==0){//如果当前像素点到直线起点的距离小于或等于偏移量,或者当前像素位置是第一帧,直接输出当前像素位置printf("%d,%d",j,i);}else{//否则,根据dda算法的公式计算新的像素位置并输出new_x=start_x+(j-WIDTH/2)*dx/delta;new_y=start_y+(i-HEIGHT/2)*dy/delta;printf("%d,%d",new_x,new_y);}}printf("\n");//换行}}intmain(){intstart_x=50,start_y=50;//直线起点坐标intend_x=200,end_y=150;//直线终点坐标draw_line(start_x,start_y,end_x,end_y);//绘制直线并输出结果return0;}```这段代码通过循环迭代的方式,逐点更新像素位置,从而实现直线的绘制。
分治法经典案例

分治法经典案例
嘿,大家知道吗,这分治法可真是太厉害啦!就拿排序来说吧,比如一堆杂乱无章的数字,哎呀呀,那简直是一团乱麻!这时候分治法就出马啦。
想象一下,你要整理一个超级乱的房间,你会怎么做?当然是把房间分成几个区域,一个区域一个区域地整理呀,分治法就类似这个道理。
比如说归并排序,它就是把这堆数字不断地分成两半,再把两半合起来,就像你把房间先分成左边和右边,分别整理好后再合到一起。
再说说在图像识别里的应用。
假如你面前有一张超级复杂的图片,里面有各种形状、各种颜色的东西,哇,这要怎么搞清楚啊!但用了分治法,就像是把这张图片切成小块,一块一块地去识别、理解。
就好像你认识一个新朋友,你会先看他的脸,再看他的衣服,一步一步慢慢了解,对吧?
还有啊,在解决复杂的计算问题时,分治法也能大显身手。
好比你要算一道超级复杂的数学题,直接去算可能会让你头大,但是通过分治法,把问题分成小份,逐个击破。
就像你打游戏,一个大 boss 你一下打不过,那就一点一点地削弱它呀!
分治法不就是这样神奇而好用的东西吗?它能把超级复杂、看似不可能完成的任务,变得有条有理,能够被我们一步一步地解决掉。
所以说呀,分
治法真的是我们的好帮手,难道不是吗?它就像一把神奇的钥匙,能打开那些看似紧闭的难题大门,让我们在解决问题的道路上一路畅通无阻!这就是分治法的厉害之处,大家可千万别小瞧它哟!。
分治算法的例子

分治算法的例子1. 哎呀,你知道吗,比如有一个大任务是把一堆杂乱的数字排序。
这就好像整理一个超级乱的房间一样。
我们可以把这堆数字分成两部分,分别排序,然后再合起来,这就是分治算法呀!就像你先整理房间的左边,再整理右边,最后整个房间就整齐啦!2. 嘿,想象一下要在一个巨大的图书馆里找一本书。
我们可以把图书馆分成几个区域,每个区域再派人去找,这也是分治算法呀!难道不是很神奇吗?就像大家分工合作去找那本神秘的书。
3. 哇哦,你看计算一个很大很大的矩阵的乘法。
这简直像一座难以翻越的大山!但我们可以把它分成小块,分别计算,再组合起来,这不就是分治算法的魅力吗?就如同一点点攻克一座高山。
4. 你想想,要解决一个超级复杂的迷宫问题。
我们可以把迷宫分成几个部分呀,一部分一部分地去探索,然后汇总结果,这不是分治算法在起作用吗?这多像一点一点解开迷宫的秘密呀!5. 嘿呀,比如统计一个很大区域里的人口数量。
我们可以把这个区域划分成小块,分别统计,最后汇总,这就是分治算法呀!跟把一个大蛋糕切成小块来数有什么区别呢!6. 哎呀呀,要找出一堆物品中最重的那个。
我们可以把物品分成几组,找出每组最重的,再比较,这不就是用了分治算法嘛!是不是很像在一堆宝藏中找最耀眼的那颗宝石呀!7. 哇塞,要对一个超级长的字符串进行操作。
那我们就把它分成小段来处理嘛,这就是分治算法的精彩之处呀!好比把一条长长的绳子分段来摆弄。
8. 你瞧,像解决一个大的图像识别问题。
我们把图像分成小部分,一部分一部分地去分析识别,最后拼起来,这绝对是分治算法的厉害所在!就如同一片片拼凑出一幅美丽的图画。
我的观点结论就是:分治算法真的是超厉害的,它能把复杂的大问题化简,就像一把神奇的钥匙能打开很多难题的大门!。
【算法复习二】传统基本算法(分治----残缺棋盘问题)

【算法复习⼆】传统基本算法(分治----残缺棋盘问题)• 问题描述:残缺棋盘是⼀个有2k×2k (k≥1)个⽅格的棋盘,其中恰有⼀个⽅格残缺。
如图给出k=1时各种可能的残缺棋盘,其中残缺的⽅格⽤阴影表⽰。
• 残缺棋盘问题就是要⽤这四种三格板覆盖更⼤的残缺棋盘。
在此覆盖中要求:1)两个三格板不能重叠2)三格板不能覆盖残缺⽅格,但必须覆盖其他所有的⽅格。
⼩格⼦数(2k×2k -1)三格板中⼩格⼦数3。
所以所需要的三格板总数为(2k×2k -1 )/3。
• 例如,⼀个4*4的残缺棋盘2k*2k以k=2时的问题为例,⽤⼆分法进⾏分解,得到的四个k=1的棋盘。
但要注意这四个棋盘,并不都是与原问题相似且独⽴的⼦问题。
因为当如图中的残缺⽅格在左上部时,第1个⼦问题与原问题相似,⽽右上⾓、左下⾓和右下⾓三个⼦棋盘(也就是图中标识为2、3、4号⼦棋盘),并不是原问题的相似⼦问题,⾃然也就不能独⽴求解了。
当使⽤⼀个①号三格板覆盖2、3、4号三个⼦棋盘的各⼀个⽅格后,我们把覆盖后的⽅格,也看作是残缺⽅格(称为“伪”残缺⽅格),这时的2、3、4号⼦问题就是独⽴且与原问题相似的⼦问题了。
• 问题分析从以上例⼦还可以发现当残缺⽅格在第1个⼦棋盘,⽤①号三格板覆盖其余三个⼦棋盘的交界⽅格,可以使另外三个⼦棋盘转化为独⽴⼦问题;当残缺⽅格在第2个⼦棋盘时,则⾸先⽤②号三格板进⾏棋盘覆盖当残缺⽅格在第3个⼦棋盘时,则⾸先⽤③号三格板进⾏棋盘覆盖当残缺⽅格在第4个⼦棋盘时,则⾸先⽤④号三格板进⾏棋盘覆盖,这样就使另外三个⼦棋盘转化为独⽴⼦问题。
程序代码思路:表⽰⽅法:每个三格板需要⽤同⼀个数字表⽰,不同三格板编号不同。
源码:#include <iomanip>using namespace std;int board[100][100]; //存放棋盘L 型的标号数组;int tile=1; // L 型⾻牌号void chessBoard(int tr, inttc, int dr, int dc, int size){if (size==1)return; int t = tile++; // L 型⾻牌号 int s = size/2; // 分割棋盘//________________________________________________ 覆盖左上⾓分治递归执⾏步骤: 1)chessBoard(0, 0, 0, 0, 4); { t=1; s=2; chessBoard(0, 0, 0, 0, 2); { t=2; s=1; chessBoard(0, 0, 0, 0, 1); { s==1 return}以下三步将左上⾓三格板⽤t=2覆盖 }return以下三步对右上递归先⽤t=1 覆盖左下左下递归先⽤t=1 覆盖右上右下递归先⽤t=1 覆盖左上递归处理类似。
分治练习题

分治练习题一、基础概念理解1. 请简述分治算法的基本思想。
2. 举例说明分治算法在解决具体问题时的步骤。
3. 请解释分治算法与递归算法之间的关系。
二、数组操作4. 给定一个整数数组,使用分治算法找出数组中的最大值。
5. 给定一个整数数组,使用分治算法找出数组中的最小值。
6. 给定一个整数数组,使用分治算法将数组排序。
7. 给定一个整数数组,使用分治算法计算数组中所有元素的和。
8. 给定一个整数数组,使用分治算法找出数组中的中位数。
9. 给定一个整数数组,使用分治算法找出数组中所有奇数的和。
三、搜索问题10. 给定一个已排序的整数数组,使用分治算法实现二分查找。
11. 给定一个整数数组,使用分治算法找出一个特定元素的索引。
12. 给定一个整数数组,使用分治算法找出第一个大于给定值的元素。
13. 给定一个整数数组,使用分治算法找出一个小于给定值的元素。
四、数学问题14. 使用分治算法计算两个大整数的乘积。
15. 使用分治算法计算一个整数的阶乘。
16. 使用分治算法计算斐波那契数列的第n项。
17. 使用分治算法计算一组数的最大公约数。
18. 使用分治算法计算一组数的最小公倍数。
五、动态规划与分治19. 使用分治算法解决最长公共子序列问题。
20. 使用分治算法解决最长公共子串问题。
21. 使用分治算法解决矩阵链乘问题。
22. 使用分治算法解决最优二叉搜索树问题。
23. 使用分治算法解决活动选择问题。
六、图论问题24. 使用分治算法计算无向图的最小树。
25. 使用分治算法计算有向图的最短路径。
26. 使用分治算法计算无向图的欧拉回路。
27. 使用分治算法计算有向图的哈密顿回路。
七、综合应用28. 使用分治算法解决归并排序问题。
29. 使用分治算法解决快速排序问题。
30. 使用分治算法解决动态规划中的背包问题。
31. 使用分治算法解决动态规划中的最长递增子序列问题。
32. 使用分治算法解决动态规划中的最长有效括号问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录
1031 输油管道问题 (1)
解题思路 (1)
程序代码 (1)
1032 邮局选址 (4)
解题思路 (4)
程序源代码 (4)
1034 集合划分2 (6)
解题思路: (6)
程序源代码: (6)
1033 集合划分 (8)
解题思路 (8)
程序源代码 (8)
1031 输油管道问题
解题思路
本题目可以分为两个步骤:
1、找出主管道得位置;
2、根据主管道得位置,计算各个油井到主管道得长度之与。
根据题意,设主管道贯穿东西,与y 轴平行。
而各个子油井则分布在主输油管道得上下两侧。
如下图:
由上图,其实只需要确定主管道得y 坐标,而与各个子油井得x 坐标无关!根据猜测,易知:主管道得y 坐标就就是所有子油井y 坐标得中位数。
(可以用平面几何知识证明,略)
求中位数得方法可以用排序后取a[(left+right)/2],当然更推荐用书上得线性时间选择算法解决。
记求得得主管道为,最后要输出得结果只需要计算:,输出即可。
另外要提醒得就是本题多Case。
程序代码
#include<stdio、h>
#include<stdlib、h>
void s &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
//本函数求arr[p:q]得一个划分i,使arr[p:i-1]都小于arr[i],arr[i+1,q]都大于arr[i]
int partition(int *arr,int p,int q)
{
int index = p-1,start = p,base = arr[q];
for(;start<q;start++)
{
if(arr[start]<=base)
{
s[start],arr[++index]);
}
}
s[++index],arr[q]);
return index;
}
//快速排序
void qsort(int *arr,int p ,int q)
{
if(p<=q)
{
int pos = partition(arr,p,q);
qsort(arr,p,pos-1);
qsort(arr,pos+1,q);
}
}
int arr[10001];
int main()
{
int n;
//注意多case 写法
while(scanf("%d",&n)!=EOF)
{
//读取数据
for(int i=0;i<n;i++)
{
//读取y
scanf("%d %d",&arr[i],&arr[i]);
}
//排序
qsort(arr,0,n-1);
//取中位数得下标mid,然后计算距离
long long sum = 0;
int mid = arr[n/2];
for(int i=0;i<n;i++)
{
sum += abs(mid - arr[i]);
}
printf("%I64d\n",sum);
}
return 0;
}
1032 邮局选址
解题思路
本题与上一题非常类似,这次就是要找出在居民点中邮局得最佳位置。
很容易想到,这次不仅要确定y 坐标,还要确定x 坐标。
类似猜想可以知道,邮局最佳位置应该为:
等于所有居民点x坐标得中位数;
等于所有居民点y 坐标得中位数;
分别求中位数得过程与上题类似,不再陈述。
最终得计算结果:要求距离之与,输出。
程序源代码
#include<stdio、h>
#include<stdlib、h>
#include<algorithm>
using namespace std;
int x[10000],y[10000];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
//读取x 与y 坐标
for(int i=0;i<n;i++)
{
scanf("%d %d",&x[i],&y[i]);
}
//调用STL中得排序算法,分别对x 坐标与y 坐标进行排序
sort(x,x+n);
sort(y,y+n);
//取x,y 坐标得中位数并计算距离
int midx = x[n/2];
int midy = y[n/2];
long long res = 0;
for(int i = 0;i < n;i++)
{
res += abs(midx-x[i]);
res += abs(midy-y[i]);
}
// 输出结果
printf("%I64d\n",res);
}
return 0;
}
1034 集合划分2
解题思路:
递推公式如下:
F (n,m) =m*F (n −1,m)+F (n −1,m −1)
F(n,m)表示把n 个元素得集合分为m 个子集,有多少种分法。
证明如下:
n 个元素得集合可以划分为F(n,m)个不同得由m 个非空子集组成得集合。
考虑3 个元素得集合,可划分为
① 1 个子集得集合:{{1,2,3}}
② 2 个子集得集合:{{1,2},{3}},{{1,3},{2}},{{2,3},{1}}
③ 3 个子集得集合:{{1},{2},{3}}
∴F(3,1)=1;F(3,2)=3;F(3,3)=1;
如果要求F(4,2)该怎么办呢?
A、往①里添一个元素{4},得到{{1,2,3},{4}}
B、往②里得任意一个子集添一个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)+2*F(3,2)=1+2*3=7
推广,得F(n,m)=F(n-1,m-1)+m*F(n-1,m)
提醒:由于本题数据范围比较大,需要用64 位长整型即__int64 或者long long。
程序源代码:
#include<stdio、h>
//计算把含有n 个元素得集合分割为m 个子集,有多少种解决方案
long long divide(int n,int m)
{
if(m==1 || m==n)
{
return 1;
}
else
{
return divide(n-1,m-1)+m*divide(n-1,m);
}
}
int main()
{
int n,m;
//多case 输入
while(scanf("%d%d",&n,&m)!=EOF)
{
printf("%I64d\n",divide(n,m));
}
return 0;
}
1033 集合划分
解题思路
假定F(n,m)表示整数n得m划分,则整数n得所有划分就是:。
提醒:
1)由于本题数据范围比较大,需要用64 位长整型即__int64 或者long long。
2)如果n比较大得话,递归算法计算时间会比较长,最好用动态规划算法实现。
程序源代码
#include<stdio、h>
//计算把含有n 个元素得集合分割为m 个子集,有多少种解决方案
long long subset(int n,int m)
{
if(n == m || m == 1)
{
return 1;
}
else
{
return subset(n-1,m-1) + m * subset(n-1,m);
}
}
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
long long sum = 0;
//计算subset(n,i)之与
for(int i=1;i<=n;i++)
{
sum+=subset(n,i);
}
printf("%I64d\n",sum);
}
return 0;
}。