zoukankan      html  css  js  c++  java
  • 第二章-递归与分治策略

    第一题:

    问题名称:整数划分问题。

    问题描述:正整数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 }
    View Code

    递归:

    有重复元素的排列问题:

    给定一个集合R={r1, ... , rn},其中的元素可能相同。求R的所有不同的排列。

    算法分析:

    输出的排列有重复,是因为输入的集合可能含有重复的元素。首先要学会演算,在演算的过程中,可以发现,如果递归的每一层,对于不同的递归/排列(这个就要在isRepeat函数中理解了),出现重复元素,那么产生的两个分支是完全一样的。——所以出现重复元素,那么此次就不用排列了,因为前面已经有了。

    设Ri=R-{ri},集合X的全排列(所有排列)为Perm(X),而(ri)Perm(Ri)表示在Perm(Ri)的所有排列前面加上ri。

    所以,R的全排列可以定义为:

      1. 出口:当n=1时,Perm(R) = r 。
      2. 产生递归:当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矩阵乘法:

    组合问题中的分治法:

    棋盘覆盖问题:

    排序问题中的分治法:

    几何问题中的分治法:

  • 相关阅读:
    c++的输入流基础知识
    用英文加优先级来解读C的声明
    django 用imagefiled访问图片
    关于Django中的表单验证
    c#语言的一些复习
    IIS发布的网站用localhost可以访问,改成IP就无法访问的解决方案 .
    首次关于IIS配置遇到的一些问题
    常见dos操作
    vs2012中对于entity framework的使用
    几个知识点
  • 原文地址:https://www.cnblogs.com/quanxi/p/5998211.html
Copyright © 2011-2022 走看看