中级软件设计师下午题:试题四

一.回溯法

 

1.非递归求解N皇后

#include <math.h>

#include <stdio.h>

#define N 10

int q[N + 1]; // 存储皇后的列号

int check(int j) { // 检查第 j 个皇后的位置是否合法

int i;

for (i = 1; i < j; i ++ ) {

if (q[i] == q[j] || abs(i - j) == abs(q[i] - q[j])) { // 判断是否在同一列和同一斜线上

return 0;

}

}

return 1;

}

void queen() { // 求解 N 皇后 方案

int i;

for (i = 1; i <= N; i ++ ) {

q[i] = 0;

}

int answer = 0; // 方案数

int j = 1; // 表示正在摆放第 j 个皇后

while (j >= 1) {

q[j] = q[j] + 1; // 让第 j 个皇后向后一列摆放

while (q[j] <= N && !check(j)) { // 判断第 j 个皇后的位置是否合法

q[j] = q[j] + 1; // 不合法就往后一个位置摆放

}

if (q[j] <= N) { // 表示第 j 个皇后的找到一个合法的摆放位置

if (j == N) { // 找到了 N 皇后的一组解

answer = answer + 1;

printf("方案%d:", answer);

for (i = 1; i <= N; i ++ ) {

printf("%d ", q[i]);

}

printf("\n");

} else {

j = j + 1; // 继续摆放下一个皇后

}

} else { // 表示第 j 个皇后找不到一个合法的摆放位置

q[j] = 0; // 还原第 j 个皇后的位置

j = j - 1; // 回溯

}

}

}

int main() {

queen();

return 0;

}

2.递归求解N皇后

#include <math.h>

#include <stdio.h>

#define N 10

int answer = 0;

int q[N + 1]; // 存储皇后的列号

int check(int j) { // 检查第 j 个皇后的位置是否合法

int i;

for (i = 1; i < j; i ++ ) {

if (q[i] == q[j] || abs(i - j) == abs(q[i] - q[j])) { // 判断是否在同一列和同一斜线上

return 0;

}

}

return 1;

}

void queen(int j) {

int i;

for (i = 1; i <= N; i ++ ) {

q[j] = i;

if (check(j)) { // 当摆放的皇后位置为合法时

if (j == N) { // 找到了 N 皇后的一组解

answer = answer + 1;

printf("方案%d:", answer);

for (i = 1; i <= N; i ++ ) {

printf("%d ", q[i]);

}

printf("\n");

} else {

queen(j + 1); // 递归摆放下一个皇后的位置

}

}

}

}

int main() {

queen(1);

return 0;

}

二.分治法

 

1.归并排序

#include <stdio.h>

#include <sched.h>

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 + i];

}

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 = (p + r) / 2;

MergeSort(A, p, q);

MergeSort(A, q + 1, r);

Merge(A, p, q, r);

}

}

int main() {

int A[] = {4, 1, 3, 6, 8, 5, 2, 9};

MergeSort(A, 0, 7);

int i;

for (i = 0; i < 8; i ++ ) {

printf("%d ", A[i]);

}

return 0;

}

2.最大子段和问题

#include <stdio.h>

#include <stdlib.h>

int MaxSubSum(int *Array, int left, int right) {

int sum = 0;

int i;

if (left == right) {

if (Array[left] > 0)

sum = Array[left];

else

sum = 0;

} else {

int center = (left + right) / 2;

int leftSum = MaxSubSum(Array, left, center);

int rightSum = MaxSubSum(Array, center + 1, right);

int s1 = 0;

int lefts = 0;

for (i = center; i >= left; i -- ) {

lefts += Array[i];

if (lefts > s1)

s1 = lefts;

}

int s2 = 0;

int rights = 0;

for (i = center + 1; i <= right; i ++ ) {

rights += Array[i];

if (rights > s2)

s2 = rights;

}

sum = s1 + s2;

if (sum < leftSum)

sum = leftSum;

if (sum < rightSum)

sum = rightSum;

}

return sum;

}

int main() {

int *Array = (int *) malloc(6 * sizeof(int));

Array[0] = -2;

Array[1] = 11;

Array[2] = -4;

Array[3] = 13;

Array[4] = -5;

Array[5] = -2;

int result = MaxSubSum(Array, 0, 5);

printf("%d", result);

return 0;

}

三.动态规划

动态规划法的经典问题:0-1背包、矩阵连乘、最长公共序列

0-1背包问题的时间复杂度和空间复杂度均为,

 

其中n是物品数量,w是背包容量。

矩阵连乘的时间复杂度为,空间复杂度为

两个矩阵 和 相乘的次数为:

相乘之后得到新的矩阵为:

例如:

 

相乘的次数为:

相乘之后得到新的矩阵为:

最长公共序列的时间复杂度为

0-1背包问题

#include <stdio.h>

#define N 4 // 物品数量

#define W 5 // 背包容量

int max(int a, int b) {

return a > b ? a : b;

}

int main() {

int v[] = {0, 2, 4, 5, 6}; // 物品价值数组

int w[] = {0, 1, 2, 3, 4}; // 物品重量数组

int fN + 1 = {}; // 子问题解数组

int i, j;

for (i = 1; i <= N; i ++ ) {

for (j = 1; j <= W; j ++ ) {

fi = fi - 1; // 默认不选第 i 个物品

if (j >= w[i]) { // 选第 i 个物品的前提条件

// 等于 不选第 i 个物品 和 选第 i 个物品 两者的较大值

fi = max(fi, fi - 1] + v[i]);

}

// 上方是写法 1

/* ============================================================ */

// 下方是写法 2

/*

if (j >= w[i]) { // 选第 i 个物品的前提条件

// 等于 不选第 i 个物品 和 选第 i 个物品 两者的较大值

fi = max(fi - 1, fi - 1] + v[i]);

} else { // 不选第 i 个物品

fi = fi - 1; // 等于 从前 i - 1 个物品中选,背包容量为 j 时的最大价值

}

*/

}

}

printf("%d\n", fN);

for (i = 0; i <= N; i ++ ) {

for (j = 0; j <= W; j ++ ) {

printf("%d ", fi);

}

printf("\n");

}

return 0;

}

四.贪心算法

部分背包问题

#include <stdio.h>

#define N 5 // 物品数量

#define W 10 // 背包容量

int v_temp[N + 1], w_temp[N + 1]; // 物品价值数组 和 物品重量数组的临时数组

double vw_temp[N + 1]; // 物品单位重量价值数组的临时数组

double answer[N + 1]; // 解方案数组

// 归并排序

void merge_sort(int v[], int w[], double vw[], int l, int r) {

if (l >= r) return;

int mid = l + r >> 1;

merge_sort(v, w, vw, l, mid), merge_sort(v, w, vw, mid + 1, r);

int i = l, j = mid + 1, k = 1;

while (i <= mid && j <= r)

{

if (vw[i] >= vw[j]) { // 按照 物品单位重量价值数组 从大到小的顺序排序

vw_temp[k] = vw[i];

v_temp[k] = v[i];

w_temp[k] = w[i];

k ++ , i ++ ;

} else {

vw_temp[k] = vw[j];

v_temp[k] = v[j];

w_temp[k] = w[j];

k ++ , j ++ ;

}

}

while (i <= mid) {

vw_temp[k] = vw[i];

v_temp[k] = v[i];

w_temp[k] = w[i];

k ++ , i ++ ;

}

while (j <= r) {

vw_temp[k] = vw[j];

v_temp[k] = v[j];

w_temp[k] = w[j];

k ++ , j ++ ;

}

for (i = l, j = 1; i <= r; i ++ , j ++ ) {

vw[i] = vw_temp[j];

v[i] = v_temp[j];

w[i] = w_temp[j];

}

}

// 显示物品价值、重量、单位重量价值数组

void show(int v[], int w[], double vw[]) {

int i;

printf("物品价值数组:");

for (i = 1; i <= N; i ++ ) printf("%d ", v[i]);

printf("\n");

printf("物品重量数组:");

for (i = 1; i <= N; i ++ ) printf("%d ", w[i]);

printf("\n");

printf("物品单位重量价值数组:");

for (i = 1; i <= N; i ++ ) printf("%.1lf ", vw[i]);

printf("\n");

}

// 求解部分背包问题最优解

double Max_Value(int v[], int w[], double vw[]) {

double result = 0.0;

int i;

int W_temp = W;

for (i = 1; i <= N; i ++ ) {

if (W_temp >= w[i]) { // 当前背包容量 大于等于 物品重量 就直接全部装入到背包中

answer[i] = 1.0;

result = result + v[i];

W_temp = W_temp - w[i];

} else { // 当前背包容量 小于 物品重量 就应该将该物品的一部分装入到背包中

break;

}

}

if (W_temp > 0 && i <= N) { // 当前背包还有剩余容量 并且 还有可选的物品

answer[i] = (double) W_temp / w[i];

result = result + W_temp * vw[i];

// result = result + (double) W_temp / w[i] * v[i];

}

return result;

}

int main() {

int v[] = {0, 6, 3, 5, 4, 6}; // 物品价值数组

int w[] = {0, 2, 2, 6, 5, 4}; // 物品重量数组

double vw[N + 1]; // 物品单位重量价值数组

int i;

// 初始化 物品单位重量价值数组

for (i = 1; i <= N; i ++ ) vw[i] = (double) v[i] / w[i];

printf("排序前:\n");

show(v, w, vw);

merge_sort(v, w, vw, 1, N);

printf("排序后:\n");

show(v, w, vw);

double result = Max_Value(v, w, vw);

printf("\nresult = %.2lf\n", result);

printf("\n");

printf("解方案结果:");

for (i = 1; i <= N; i ++ ) printf("%.1lf ", answer[i]);

return 0;

}

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值