软考--算法

190 阅读5分钟

一、分治法

image.png

image.png

image.png

//
// Created by zg on 2023/10/5.
//
#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,7,5,2,9};
    MergeSort(A,0,7);

    for (int i = 0; i < 8; ++i) {
        printf("%d",A[i]);
    }
    return 0;
}

image.png

image.png

//
// Created by zg on 2023/10/12.
//
#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;
}

image.png

image.png

image.png

image.png

image.png

二、动态规划

image.png

image.png

1、0-1背包问题

image.png

image.png

image.png

image.png

//
// Created by zg on 2023/10/6.
//
#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 f[N + 1][W + 1] = {}; // 存放子问题解数组

    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= W; ++j) {
            f[i][j] = f[i - 1][j]; //默认不选第i个物品

            if(j >= w[i]){ //选第i个物品的前提条件
                //等于 不选第i个物品 和选择第i个物品的较大值
                f[i][j] = max(f[i][j],f[i - 1][j - w[i]] + v[i]);
            }
        }
    }
    printf("%d\n",f[N][W]);
    for (int i = 0; i <= N; ++i) {
        for (int j = 0; j <= W; ++j) {
            printf("%d ",f[i][j]);
        }
        printf("\n");
    }
    return 0;
}

2、时间复杂度

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

三、贪心

image.png

image.png

1、部分背包问题

image.png

image.png

//
// Created by zg on 2023/10/6.
//
#include <stdio.h>

#define N 5//物品数量

#define W 100 //背包容量

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;

            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];
        }
    return  result;
}

int main(){

    int v[] = {0,60,65,40,30,20};
    int w[] = {0,50,30,40,20,10};

    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 = %.1lf\n",result);
    printf("\n");

    printf("解决方案:");

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

    return 0;
}

image.png

image.png

image.png

image.png

image.png

四、回溯

image.png

image.png

1、N皇后问题

image.png

image.png

#include <stdio.h>
#include<math.h>

#define N 4
//非递归
int q[N+1];// 存储皇后的列号

int check(int j){ //检查第j个皇后的位置是否合法
    int i ;
    for ( i = 0; 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 = 0; 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){
            if(j == 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;
}
//
// Created by zg on 2023/10/5.
//
#include <stdio.h>
#include<math.h>
#define N 4
// 递归皇后问题
int q[N+1];// 存储皇后的列号

int answer = 0; //方案数

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){ //求解N皇后方案
    int i ;
    for ( i = 1; i <= N; ++i) {
        q[j] = i;

        if(check(j)){
            if(j == 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;
}

image.png

image.png

五、分支限界法

image.png

综合

image.png

image.png

image.png

image.png

image.png

image.png

image.png