递归

递归汉诺塔
void HanoiRecursion(const int n, const char a, const char b, const char c) {
    if (1 == n) 
        cout << a << "->" << c << endl;
    else {
        HanoiRecursion(n-1, a, c, b);
        cout << a << "->" << c << endl;
        HanoiRecursion(n-1, b, a, c); 
    }
}
迭代汉诺塔
struct HanoiState {
    HanoiState(const int n, const char a, const  char b, const char c) : n_(n), a_(a), b_(b), c_(c) {}
    const int n_; const char a_, b_, c_;
};
void HanoiIteration(const int n, const int a, const int b, const int c) {
    stack<HanoiState> s;
    s.push(HanoiState(n, a, b, c));
    int n_; char a_, b_, c_;
    while (!s.empty()) {
        HanoiState hs = s.top();
        s.pop();
        n_ = hs.n_; a_ = hs.a_; b_ = hs.b_; c_ = hs.c_;
        if (1 == n_) 
            cout << a_ << "->" << c_ << endl;
        else {
            s.push(HanoiState(n_-1, b_, a_, c_));
            s.push(HanoiState(1, a_, b_, c_));
            s.push(HanoiState(n_-1, a_, c_, b_));
        }
    }
}

全排列
// 123 132 213 231 312 321
// 全排列就是从第一个数字起每个数分别与它后面的数字交换
void permutation(char *arr, const int s, const int e) {
    if (s == e) {
        for (int i = 0; i < e; ++i)
            cout << arr[i];
        cout << endl;
    } else {
        for (int i = s; i < e; ++i) {
            swap(arr[s], arr[i]);
            permutation(arr, s+1, e);
            swap(arr[s], arr[i]);
        }
    }
}
不重复的全排列
// 去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换
// 即:当第i与j元素交换时,要求[i, j)区间内,没有与j相等的数
bool NeedSwap(const char *arr, int s, int e) {
    for (int i = s; i < e; ++i)
        if (arr[i] == arr[e])
            return false;
    return true;
}
void PermutationRecursionWithoutRepeat(char *arr, const int s, const int e) {
    if (s == e) {
        copy(arr, arr + e, ostream_iterator<char>(cout));
        cout << endl;
    } else {
        for (int i = s; i <  e; ++i)
            if (NeedSwap(arr, s, i)) {
                swap(arr[s], arr[i]);
                PermutationRecursionWithoutRepeat(arr, s + 1, e);
                swap(arr[s], arr[i]);
            }
    }
}
迭代全排列
// 考虑926520字符串,从后向前找第一对相邻的递增数字,26满足要求,
// 则2为替换数,且为替换点;从后向前找到第一个比替换数大的数,找到5,
// 将2和5交换,然后反转后面的6220字符串,得到950226
bool NextPermutation(char * const arr) {
    char *last = arr + strlen(arr); 
    if (last == arr)
        return false;
    char *i = last - 1;
    char *ii;
    while (i != arr)
    {
        ii = i--;
        if (*i < *ii) {
            char *j = last;
            while (*--j <= *i)
                ;
            swap(*i, *j);
            reverse(ii, last);
            return true;
        }
    }
    reverse(i, last);
}
DFS全排列
const int MaxArrSize = 100;
bool g_used[MaxArrSize];
char arr[] = {'a','b','c'};
char tmp[MaxArrSize];
void PermutationDFS(const char *arr, char *res, const int pos, const int len) {
    if (pos == len) {
        copy(res, res+len, ostream_iterator<char>(cout));
        cout << endl;
    } else
        for (int i = 0; i < len; ++i)
            if (!g_used[i]) {
                g_used[i] = true;
                res[pos] = arr[i];
                PermutationDFS(arr, res, pos + 1, len);
                g_used[i] = false;
            }
}

整数划分
将最大加数n1不大于m的划分个数记作q(n,m):
  1. q(n,m)=1,n=1                              1只有一种分法
  2. q(n,m)=1,n>=1,m=1                         最大加数为1,只有一种分法
  3. q(n,m)=1+q(n,m-1),n=m                     正整数n的划分由本身及m<=n-1的划分组成
  4. q(n,m)=q(n,m-1)+q(n-m,m),n>m>1            减去m后,可能还可以用m划分
  5. q(n,m)=q(n,n),m>n                         最大加数不能大于n
int q(const int n, const int m) {
    if (n < 1 || m < 1) return 0;
    if (1 == n|| 1 == m) return 1;
    if (n < m) return q(n, n);
    if (n == m) return 1 + q(n, m-1);
    if (n > m && m > 1) return q(n, m -1) + q(n - m, m);
}
奇数划分
int q(const int n, const int m) {
    if (n < 1 || m < 1) return 0;
    if (1 == n|| 1 == m) return 1;
    if (n < m) return q(n, n);
    if (n == m && n % 2 == 0) return q(n, m-1);    // n为偶数,则自身不是一种划分
    if (n == m && n % 2 == 1) return 1 + q(n, m-1);
    if (n > m && m % 2 == 0) return q(n, m -1);    // 最大加数为偶数,需要将其变为奇数
    if (n > m && m % 2 == 1) return q(n, m -1) + q(n - m, m);
}
不同因子划分
int q(const int n, const int m) {
    if (n < 1 || m < 1) return 0;
    if (1 == n|| 1 == m) return 1;
    if (n < m) return q(n, n);
    if (n == m) return 1 + q(n, n-1);
    return q(n, m - 1) + q(n - m, m - 1);
}

集合划分
Stirling(斯特灵)
{{1,2,3,4}} Stirling(4,1)=1;
{{1,2},{3,4}}...{{2,3,4},{1}} Stirling(4,2)=7;
{{1,2},{3},{4}}...{{3,4},{1},{2}} Stirling(4,3)=6;
{{1},{2},{3},{4}} Stirling(4,4)=1
Stirling(n,m):
  1. S(n, m) = m * S(n-1, m) + S(n-1, m-1);     某个数单独一个子集+某个数在m个子集中
  2. S(n, m) = 0; m > n;                        要分自己数量大于元素数量
  3. S(n, 0) = 0;                               分成m个子集,但是元素有剩余
  4. S(0, 0) = 1;                               所有元素分成了m个子集
int S(const int n, const int m) {
    if (m > n) return 0;
    if (0 != n && 0 == m) reutrn 0;
    if (0 == n && 0 == m) return 1;
    return m * S(n-1, m) + S(n-1, m-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值