软考中级-软件设计师-19.下午题-试题四[算法](15分)

0 阅读5分钟

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]);
}

19.6 21年下半年下午题试题4