递归汉诺塔
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相等的数
// 即:当第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):
- q(n,m)=1,n=1 1只有一种分法
- q(n,m)=1,n>=1,m=1 最大加数为1,只有一种分法
- q(n,m)=1+q(n,m-1),n=m 正整数n的划分由本身及m<=n-1的划分组成
- q(n,m)=q(n,m-1)+q(n-m,m),n>m>1 减去m后,可能还可以用m划分
- 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):
- S(n, m) = m * S(n-1, m) + S(n-1, m-1); 某个数单独一个子集+某个数在m个子集中
- S(n, m) = 0; m > n; 要分自己数量大于元素数量
- S(n, 0) = 0; 分成m个子集,但是元素有剩余
- 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);
}