第一题:
问题名称:整数划分问题。
问题描述:正整数n可以表示为一系列正整数之和:n = n1 + n2 + ... + nk (k>=1, n1>=n2>=nk ),则称这种表示为正整数n的划分,不同的这种表示的个数称为正整数n的划分数,记为p(n)。在所有划分中,将最大加数n1不大于m的划分数,记为q(n,m)。
问题分析:
q(n, m) = 1 ,当n = 1,m = 1;
q(n,n) ,当n < m;
1 + q(n,n-1),当n = m;
q(n,m-1) + q(n-m,m),当n>m>1
所以得出算法:
1 #include <stdio.h> 2 3 int Division(int n, int m); 4 void main() 5 { 6 int n = 0; 7 scanf("%d", &n); 8 printf("%d ",Division(n, n)); 9 } 10 11 int Division(int n, int m) 12 { 13 if( ( n < 1 ) || ( m < 1 ) ) return 0; 14 if( ( n == 1 ) || ( m == 1 ) ) return 1; 15 if( n < m ) return Division(n, n); 16 if( n == m ) return Division(n, m - 1 ) + 1; 17 return Division(n, m - 1) + Division(n - m, m); 18 }
递归:
有重复元素的排列问题:
给定一个集合R={r1, ... , rn},其中的元素可能相同。求R的所有不同的排列。
算法分析:
输出的排列有重复,是因为输入的集合可能含有重复的元素。首先要学会演算,在演算的过程中,可以发现,如果递归的每一层,对于不同的递归/排列(这个就要在isRepeat函数中理解了),出现重复元素,那么产生的两个分支是完全一样的。——所以出现重复元素,那么此次就不用排列了,因为前面已经有了。
设Ri=R-{ri},集合X的全排列(所有排列)为Perm(X),而(ri)Perm(Ri)表示在Perm(Ri)的所有排列前面加上ri。
所以,R的全排列可以定义为:
- 出口:当n=1时,Perm(R) = r 。
- 产生递归:当n>1时,Perm(R) = (r1)Perm(R1),(r2)Perm(R2),... ,(rn)Perm(Rn)组成。
输入:第一行为元素个数n,第二行为待排列的n个数。
输出:前面几行是所有的不同的排列,最后一行是排列的总数。
代码:
#include <iostream> #include <algorithm> using namespace std; int permNumber = 0; bool isRepeat(char *R, int i, int k) { for (int j = k; j < i; j++) { if (R[i] == R[j]) return true; } return false; } void Perm(char *R, int k, int m) { if (k == m) //到最后一个元素,出口 { for (int i = 0; i <= m; i++) //因为在递归的过程中,m为变换,所以就是传进来的n-1 { cout << R[i]; } cout << endl; permNumber++; } else { for (int i = k; i <= m; i++) { if (!isRepeat(R, i, k)) { swap(R[k], R[i]); Perm(R, k + 1, m); //k就代表递归层数,即指向数组的位置 swap(R[k], R[i]); } } } } int main() { int n; char *R; cin >> n; R = new char[n]; for (int i = 0; i < n; i++) { cin >> R[i]; } cout << endl; Perm(R, 0, n - 1); cout << permNumber << endl; return 0; } /*测试数据: 输入: 4 aacc 输出: aacc acac acca caac caca ccaa 6 */
集合划分问题:
一个n元集合{1,... ,n},可以划分为若干个、由m个非空集合组成的非空子集,求出指定了m的非空子集的个数——将解设为f(n,m)。m应该在[1,n]内,规定:若m=0,则表示未指明m,输出所有的非空子集的个数。
输入:只有一行、两个数,第一个数为集合个数n、第二个数为m。
输出:当输入的m在[1,n]内时,输出为由m个非空集合组成的非空子集的个数;或者当m=0时,输出所有的非空子集的个数。
代码:
分治:分解——>求解——>合并。
数字计算问题中的分治法:
strassen矩阵乘法:
组合问题中的分治法:
棋盘覆盖问题:
排序问题中的分治法:
几何问题中的分治法: