19.1 N皇后问题(回溯法)
19.1.1 非递归算法
#include<stdio.h>
#include<math.h>
#define N 4
// 存储皇后序列
int q[N + 1];
// 检查第j个皇后位置是否合法
int check(int j) {
for (int i = 1; i < j; i++) {
// 判断是否在同一列或同一斜线
if (q[i] == q[j] || abs(i - j) == abs(q[i] - q[j])) {
return 0;
}
}
return 1;
}
// 求解N皇后问题
void queen() {
for (int i = 1; i <= N; i++) {
q[i] = 0;
}
// 方案数
int answer = 0;
// 表示正在摆放第j个皇后
int j = 1;
while (j >= 1) {
// 第j个皇后向后一列摆放
q[j] = q[j] + 1;
// 判断第j个皇后是否合法
while (q[j] <= N && !check(j)) {
// 不合法往后移动一格
q[j] = q[j] + 1;
}
// 表示第j个皇后找到的第一个合法位置
if (q[j] <= N) {
// 找到了N皇后的第一组解
if (j == N) {
// 方案数加1
answer = answer + 1;
printf("方案%d:", answer);
for (int i = 1; i <= N; i++) {
printf("%d ", q[i]);
}
printf("\n");
}
else {
// 继续放下一个皇后
j = j + 1;
}
// 表示第j个皇后找不到一个合法的位置
}
else {
// 还原第j个皇后
q[j] = 0;
// 回溯到上一个皇后
j = j - 1;
}
}
}
// 主函数
int main() {
queen();
return 0;
}
19.1.2 递归算法
#include<stdio.h>
#include<math.h>
#define N 4
// 存储皇后序列
int q[N + 1];
// 方案数
int answer;
// 检查第j个皇后位置是否合法
int check(int j) {
for (int i = 1; i < j; i++) {
// 判断是否在同一列或同一斜线
if (q[i] == q[j] || abs(i - j) == abs(q[i] - q[j])) {
return 0;
}
}
return 1;
}
// 求解N皇后问题
void queen(int j) {
for (int i = 1; i <= N; i++) {
q[j] = i;
// 当前第j个皇后找到一个合法的摆放位置
if (check(j)) {
// 找到了一组N皇后的解
if (j == N) {
// 方案数加1
answer = answer + 1;
printf("方案%d:", answer);
for (int i = 1; i <= N; i++) {
printf("%d ", q[i]);
}
printf("\n");
}else {
queen(j + 1);
}
}
}
}
int main() {
queen(1);
return 0;
}
19.2 归并排序(分治法)
时间复杂度递归式:T(n) = 2T(n/2) + O(n)
19.2.1 算法1
#include<stdio.h>
#include<stdlib.h>
#define INT_MAX 65525
void Merge(int A[], int p, int q, int r) {
int i, j, k;
int L[50], R[50];
int n1 = q - p + 1, n2 = r - q;
for (i = 0; i < n1; i++) {
L[i] = A[p + 1];
}
for (j = 0; j < n2; j++) {
R[j] = A[q + j + 1];
}
L[n1] = INT_MAX;
R[n2] = INT_MAX;
i = 0;
j = 0;
for (k = p; k < r + 1; k++) {
if (L[i] < R[j]) {
A[k] = L[i];
i++;
}else {
A[k] = R[j];
j++;
}
}
}
void MergeSort(int A[], int p, int r) {
int q;
if (p < r) {
q = (r + p) / 2;
MergeSort(A, p, q);
MergeSort(A, q + 1, r);
Merge(A, p, q, r);
}
}
int main() {
int A[] = {4, 1, 5, 7, 8, 2, 8, 9};
MergeSort(A, 0, 7);
for (int i = 0; i < 8; i++) {
printf("%d ", A[i]);
}
return 0;
}
19.2.2 算法2
1:k < r + 1
2:arr[k] = right[j]
3:begin < end
4:mergeSort(arr, mid + 1, end)
#include<stdio.h>
#include<stdlib.h>
#define MAX 65525
void merge(int arr[], int p, int q, int r) {
int *left, *right;
int n1, n2, i, j, k;
n1 = q - p + 1;
n2 = r - q;
if((left = (int)malloc((n1 + 1) * sizeof(int))) == NULL) {
perror("malloc error");
exit(0);
}
if((right = (int)malloc((n1 + 1) * sizeof(int))) == NULL) {
perror("malloc error");
exit(0);
}
for(i = 0; i < n1; i ++) {
left[i] = arr[p + i];
}
left[i] = MAX;
for(i = 0; i < n2; i ++) {
right[i] = arr[q + i + 1];
}
right[i] = MAX;
i = 0, j = 0;
for(k = p; k < r + 1; k ++) {
if(left[i] > right[j]) {
arr[k] = right[j];
j ++;
}else {
arr[k] = left[i];
i ++;
}
}
}
void mergeSort(int arr[], int begin, int end) {
int mid;
if(begin < end) {
mid = (begin + end) / 2;
mergeSort(arr, begin, mid);
mergeSort(arr, mid + 1, end);
merge(arr, begin, mid, end);
}
}
int main() {
int arr[] = {1, 3, 6, 7, 2, 4, 9};
mergeSort(arr, 0, 6);
for(int i = 0; i < 7; i ++) {
printf("%d ", arr[i]);
}
return 0;
}
19.3 假币问题(分治法)
1:first + (last - first) / 2 + 1
2:firstSum < lastSum
3:first + (last - first) / 2
#include<stdio.h>
int getCounterfeiCoin(int coins[], int first, int last) {
int firstSum = 0, lastSum = 0;
int i;
// 只剩下两枚硬币
if(first == last - 1) {
if(coins[first] < coins[last])
return first;
return last;
}
// 偶数枚硬币
if((last - first + 1) % 2 == 0) {
for(i = first; i < first + (last - first) / 2 + 1; i ++) {
firstSum += coins[i];
}
for(i = first + (last - first) / 2 + 1; i < last + 1; i ++) {
lastSum += coins[i];
}
if(firstSum < lastSum) {
return getCounterfeiCoin(coins, first, first + (last - first) / 2);
}else {
return getCounterfeiCoin(coins, first + (last - first) / 2 + 1, last);
}
// 奇数枚硬币
}else {
for(i = first; i < first + (last - first) / 2; i ++) {
firstSum += coins[i];
}
for(i = first + (last - first) / 2; i < last + 1; i ++) {
lastSum += coins[i];
}
if(firstSum < lastSum) {
return getCounterfeiCoin(coins, first, first + (last - first) / 2 - 1);
}else if(firstSum > lastSum) {
return getCounterfeiCoin(coins, first + (last - first) / 2 + 1, last);
}else {
return first + (last - first) / 2;
}
}
}
int main() {
int coins[] = {1, 1, 1, 0, 1, 1};
int index = getCounterfeiCoin(coins, 0, 5);
printf("%d ", index);
}
19.4 希尔排序(分治法)
1:k = k / 2
2:k > 1
3:data[k - dk] > data[k]
4:data[j + dk] = t
#include<stdio.h>
#include<stdlib.h>
void shellSort(int data[], int n) {
int *delta, k, i, t, dk, j;
k = n;
delta = (int *)malloc(sizeof(int) * (n / 2));
i = 0;
do {
k = k / 2;
delta[i ++] = k;
}while(k > 1);
i = 0;
while((dk = delta[ i]) > 0) {
for(k = delta[i]; k < n; ++ k)
if(data[k - dk] > data[k]) {
t = data[k];
for(j = k - dk; j >= 0 && t < data[j]; j -= dk)
data[j + dk] = data[j];
data[j + dk] = t;
}
++ i;
}
}
int main() {
int arr[] = {78, 11, 9, 81, 40};
shellSort(arr, 5);
for(int i = 0; i < 5; i ++) {
printf("%d ", arr[i]);
}
return 0;
}
19.5 0-1背包问题
#include<stdio.h>
#define N 4
#define W 5
int max(int a, int b) {
return a > b ? a : b;
}
void main() {
int i, j;
// 物品价值数组
int v[] = {0, 2, 4, 5, 6};
// 物品重量数组
int w[] = {0, 1, 2, 3, 4};
// 子问题解数组
int f[N + 1][W + 1] = {};
for(i = 1; i <= N; i ++) {
for(j = 1; j <= W; j ++) {
/*
f[i][j] = f[i - 1][j];
if(j >= w[i]) {
f[i][j] = max(f[i][j], f[i - 1][j - w[i]] + v[i]);
}
*/
// 选第i个物品的前提条件
if(j >= w[i]) {
// 不选第i个和选第i个取最大值
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
}else {
// 不选第i个物品,背包重量为j的最大价值
f[i][j] = f[i - 1][j];
}
}
}
printf("%d ", f[N][W]);
}