算法设计与分析实验报告-分治法相关练习题

 校课程的简单实验报告。

算法设计与分析实验报告-递归与分治策略

算法设计与分析实验报告-动态规划算法

算法设计与分析实验报告-贪心算法 

        dijkstra迪杰斯特拉算法(邻接表法)

算法设计与分析实验报告-回溯法

算法设计与分析实验报告-分支限界法 

算法设计与分析实验报告-分治法相关练题

北京大学出版社-算法设计与分析


五、程序题

1. 试给出用分治法求某集合中元素值为偶数的元素个数的程序代码。

2. 试给出用i分治法求某集合中元素值为最大数的程序代码。

3. 根据分治法求某集合中元素值大于指定值的元素个数。要求给出分治法解决该问题的基本思路并给出递归实现代码。

4. 根据分治法求解棋盘覆盖问题。试写出该程序代码,可以只写函数

5. 给出归并排序的核心代码,并分析归并排序的时间复杂性。

6. 给出快速排序算法,以及快速排序的Partition函数。

7. 给出分治法设计的循环赛日程表。

8. 用分治法写出有序序列进行二分查找的过程

9. 对给定的含有n个元素的无序序列,求这个元素中第K小的元素


分治法求某集合中元素值大于指定值的元素个数。

基本思路:将求解范围l~r分为两半,变成2个子问题,递归求解两个子问题,再将两个子问题的解加和得到原问题解。 
递归出口:只有一个元素时与指定元素进行比较返回答案1或0. 
递归关系:两个子问题的解相加为原问题解。 
参数设置:数组arr,起始位置l,终点位置r,指定比较值x。

1. 试给出用分治法求某集合中元素值为偶数的元素个数的程序代码。
//
// Created by GiperHsiue on 2022/10/17.
//
// 分治法求某集合中元素值为偶数的元素个数。
#include <iostream>
using namespace std;
int check(int arr[], int l, int r){
    if(l == r) return arr[l] % 2 ? 0 : 1;
    int mid = l + r >> 1;
    return check(arr, l, mid) + check(arr, mid + 1, r);
}
int main(){
    int n;
    cin >> n;
    int *arr = new int[n];
    for(int i = 0; i < n; i ++) cin >> arr[i];
    cout << check(arr, 0, n - 1);
    return 0;
}

运行如下:


2. 试给出用分治法求某集合中元素值为最大数的程序代码。
//
// Created by GiperHsiue on 2022/10/17.
//
//分治法求某集合中元素值为最大数。
#include <iostream>
#include <algorithm>
using namespace std;
int check(int arr[], int l, int r){
    if(l == r) return arr[l];
    int mid = l + r >> 1;
    return max(check(arr, l, mid), check(arr, mid + 1, r));
}
int main(){
    int n;
    cin >> n;
    int *arr = new int[n];
    for(int i = 0; i < n; i ++) cin >> arr[i];
    cout << check(arr, 0, n - 1);
    return 0;
}

测试如下:


3. 根据分治法求某集合中元素值大于指定值的元素个数。要求给出分治法解决该问题的基本思路并给出递归实现代码。
//
// Created by GiperHsiue on 2022/10/17.
//
#include <iostream>
#include <algorithm>
using namespace std;
int check(int arr[], int l, int r, int x){
    if(l == r) return arr[l] > x ? 1 : 0;
    int mid = l + r >> 1;
    return check(arr, l, mid, x) + check(arr, mid + 1, r, x);
}
int main(){
    int n, x;
    cin >> n;
    int *arr = new int[n];
    for(int i = 0; i < n; i ++) cin >> arr[i];
    cin >> x;
    cout << check(arr, 0, n - 1, x);
    return 0;
}

测试如下:

4. 根据分治法求解棋盘覆盖问题。试写出该程序代码,可以只写函数。
//
// Created by GiperHsiue on 2022/10/20.
//
//棋盘覆盖问题
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
char tile = '1'; // 骨牌的编号
char **board;
//(r,c)棋盘左上角坐标,(sr,sc)特殊方格坐标,size棋盘的行(列)数
void cb(int r, int c, int sr, int sc, int size){
    if(size == 1) return;
    int t = tile++;
    int s = size / 2;

    //左上角
    if(sr < r + s && sc < c + s){
        cb(r, c, sr, sc, s);
    } else{
        board[r + s -1][c + s - 1] = t;
        cb(r, c, r + s - 1, c + s - 1, s);
    }

    //右上角
    if(sr < r + s && sc >= c + s){
        cb(r, c + s, sr, sc, s);
    } else{
        board[r + s -1][c + s] = t;
        cb(r, c + s, r + s - 1, c + s, s);
    }

    //左下角
    if(sr >= r + s && sc < c + s){
        cb(r + s, c, sr, sc, s);
    } else{
        board[r + s][c + s - 1] = t;
        cb(r + s, c, r + s, c + s - 1, s);
    }

    //右下角
    if(sr >= r + s && sc >= c + s){
        cb(r + s, c + s, sr, sc, s);
    } else{
        board[r + s][c + s] = t;
        cb(r + s, c + s, r + s, c + s, s);
    }
}
int main(){
    int k;
    cout << "棋盘大小2^k * 2^k 输入K:";
    cin >> k;
    int n = pow(2, k);
    board = new char*[n]; //动态创建棋盘数组
    for(int i = 0; i < n; i ++) board[i] = new char[n];
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            board[i][j] = '.';
        }
    }
    cout << "输入特殊方格位置:";
    int sr, sc;
    cin >> sr >> sc;
    board[sr][sc] = '*';
    cout << "初始化:" << endl;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            cout << setw(4) << board[i][j];
        }
        cout << endl;
    }
    cb(0, 0, sr, sc, n);
    cout << "覆盖后:" << endl;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if(i == sr && j == sc) cout << setw(4) << board[i][j];
            else cout << setw(4) << board[i][j] - '0';
        }
        cout << endl;
    }
    return 0;
}

测试如下:

5. 给出归并排序的核心代码,并分析归并排序的时间复杂性。
//
// Created by GiperHsiue on 2022/10/20.
//
//归并排序
#include <iostream>
using namespace std;
int n;

void mergeSort(int a[], int l, int r){
    if(l >= r) return;
    int mid = (l + r) / 2;
    mergeSort(a, l, mid), mergeSort(a, mid + 1, r);
    //merge过程
    int k = 0, i = l, j = mid + 1;
    int *tmp = new int[n]();
    while (i <= mid && j <= r) {
        if (a[i] <= a[j]) tmp[k++] = a[i++];
        else tmp[k++] = a[j++];
    }
    while(i <= mid) tmp[k++] = a[i++];
    while (j <= r) tmp[k++] = a[j++];
    //copy过程
    for (i = l, j = 0;i <= r; i++, j++) {
        a[i] = tmp[j];
    }
}
int main(){
    cin >> n;
    int *a = new int[n]();
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    mergeSort(a, 0, n - 1);
    for (int i = 0; i < n; ++i) {
        cout << a[i] << ' ';
    }
    return 0;
}

时间复杂度分析:T(n)=2T(n/2)+n

        通过主方法可得T(n)=O(n*logn) 

主方法公式(Master):

测试如下: 

6. 给出快速排序算法,以及快速排序的Partition函数。
//
// Created by GiperHsiue on 2022/10/20.
//
//快速排序
#include <iostream>
using namespace std;
int Partition(int a[], int l, int r){
    int x = a[l], i = l - 1, j = r + 1;
    while (i < j){
        do i++; while (a[i] < x);
        do j--; while (a[j] > x);
        if (i < j) swap(a[i], a[j]);
    }
    return j;
}
void quickSort(int a[], int l, int r){
    if (l >= r) return;
    int q = Partition(a, l, r);
    quickSort(a, l, q), quickSort(a, q + 1, r);
}

int main(){
    int n;
    cin >> n;
    int *a = new int[n];
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    quickSort(a, 0, n - 1);
    for (int i = 0; i < n; ++i) {
        cout << a[i] << ' ';
    }
    return 0;
}

测试如下:

7. 给出分治法设计的循环赛日程表。
//
// Created by GiperHsiue on 2022/10/20.
//
// 循环赛日程表
#include<iostream>
#include<cmath>
using namespace std;

void schedule(int k, int n, int** array);

int main()
{
    int k;  // 运动员的人数n=2^k
    cout << "运动员的人数为n(n=2^k),请输入k的值:";
    cin >> k;
    int n = pow(2, k);  // 运动员的人数n=2^k

    int** array = new int* [n+1]; // 循环赛日程表,动态数组的创建
    for (int i = 0;i < n+1;i++)
        array[i] = new int[n+1];

    // 填充日程表
    schedule(k, n, array);

    // 输出日程表
    cout << "\n循环赛日程表为:\n";
    for (int i = 1;i <= n;i++)
    {
        for (int j = 1;j <= n;j++)
            cout << array[i][j] << " ";
        cout << "\n";
    }
    // 删除二维数组
    for (int i = 0;i < n + 1;i++)
        delete[] array[i];
    delete[] array;
    return 0;
}

void schedule(int k, int n, int** array)   // 数组下标从1开始
{
    for (int i = 1;i <= n;i++)  // 第一行排1-n
        array[1][i] = i;

    int m = 1;  // 用来控制每一次填表时i行j列的起始填充位置

    for (int s = 1;s <= k;s++)  // k指分成k大部分进行填充日程表;s指第几大部分
    {
        n = n / 2;
        for (int t = 1;t <= n;t++)  // 第s部分内的循环
        {
            for (int i = m + 1;i <= 2 * m;i++) // 行
            {
                for (int j = m + 1;j <= 2 * m;j++) // 列
                {
                    array[i][j + (t - 1) * m * 2] = array[i - m][j + (t - 1) * m * 2 - m];       //左上角等于右下角的值
                    array[i][j + (t - 1) * m * 2 - m] = array[i - m][j + (t - 1) * m * 2];       //左下角等于右上角的值
                }
            }
        }
        m *= 2;
    }
}

测试如下:

8. 用分治法写出有序序列进行二分查找的过程。
//
// Created by GiperHsiue on 2022/10/20.
//
//二分查找,给出过程
#include <iostream>
using namespace std;
int t = 1;
int BinSearch(int a[], int l, int r, int k){
    int mid = 0;
    if(l <= r){
        mid = (l + r) / 2;
        cout << "第" << t++ << "次比较:" << " mid = " << mid << " a[mid] = " << a[mid] << endl;
        if (a[mid] == k) return mid;
        else if (a[mid] < k) return BinSearch(a, mid + 1, r, k);
        else return BinSearch(a, l, mid - 1, k);
    }
    return -1;
}
int main(){
    int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, k;
    for(auto x:a) cout << x << ' ';
    cout << endl;
    cin >> k;
    int res = BinSearch(a, 0, 9, k);
    cout << "查找结果位置下标:" << res;
    return 0;
}

测试如下:

9. 对给定的含有n个元素的无序序列,求这个元素中第K小的元素。

法1,可以利用快排思想,在快速排序基础上,在每次划分以后,判定所找元素在哪一边,再只对所在一半继续递归进行划分,直到找到确定位置返回。

法2如下;

//
// Created by GiperHsiue on 2022/10/20.
//
// 对给定的含有n个元素的无序序列,求这个序列中第k小的元素。
// 
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int select(int a[], int start, int end, int k) {
    int n = end - start;
    if (n < 5) {
        sort(a + start, a + end);
        return a[start + k - 1];
    }

    int s = n / 5;
    int *m = new int[s];   //中位数数组
    int i;
    for (i = 0; i < s; i++) {
        sort(a + start + i * 5, a + start + i * 5 + 5);
        m[i] = a[start + i * 5 + 2];
    }
    sort(m, m + i);
    int mid = m[i / 2];
    int *a1 = new int[n];
    int *a2 = new int[n];
    int *a3 = new int[n];
    int num1 = 0, num2 = 0, num3 = 0;
    for (int i = start; i < end; i++) {
        if (a[i] < mid)
            a1[num1++] = a[i];
        else if (a[i] == mid)
            a2[num2++] = a[i];
        else
            a3[num3++] = a[i];
    }
    if (num1 >= k)
        return select(a1, 0, num1, k);
    if (num1 + num2 >= k)
        return mid;
    else
        return select(a3, 0, num3, k - num1 - num2);
}

int main() {
    int n;
    cout << "输入个数n:";
    cin >> n;
    int *a = new int[n];
    cout << "输入数组元素:";
    for (int i = 0; i < n; i++)
        cin >> a[i];
    int k;
    cout << "输入所求第几小元素k:";
    cin >> k;
    cout << "第" << k << "小元素为:" << select(a, 0, n, k) << endl;
    delete[] a;
    return 0;
}

测试如下:

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是第四章的部分习题及答案,希望对你有帮助。 1. 设计一个O(nlogn)时间复杂度的算法,找出一个整数数组的最大差值,其最大值必须位于最小值之后。 解答:可以使用分治法,将数组分成两部分,分别出左边的最大值和右边的最小值,然后比较两个值之间的差值,取最大值即可。具体实现如下: ```python def max_diff(arr): if len(arr) < 2: return 0 mid = len(arr) // 2 left_max = max(arr[:mid]) right_min = min(arr[mid:]) return max(right_min - left_max, max_diff(arr[:mid]), max_diff(arr[mid:])) ``` 2. 设计一个算法,找出一个整数数组的最大子序列和。 解答:可以使用动态规划法,定义一个状态数组dp,dp[i]表示以第i个元素结尾的最大子序列和,转移方程为:dp[i] = max(dp[i-1] + arr[i], arr[i])。最后返回dp数组的最大值即可。具体实现如下: ```python def max_subarray(arr): if not arr: return 0 dp = [0] * len(arr) dp[0] = arr[0] for i in range(1, len(arr)): dp[i] = max(dp[i-1] + arr[i], arr[i]) return max(dp) ``` 3. 给定一个长度为n的整数序列,设计一个算法,找出其第k大的数。 解答:可以使用快速排序的思想,每次选定一个pivot,将数组分成两部分,左边的元素都小于pivot,右边的元素都大于等于pivot。然后比较pivot的位置和k的大小,如果pivot的位置大于k,则在左边继续查找;如果pivot的位置小于k,则在右边继续查找。具体实现如下: ```python def quick_select(arr, k): if not arr or k > len(arr): return None pivot = arr[-1] left = [x for x in arr[:-1] if x < pivot] right = [x for x in arr[:-1] if x >= pivot] if len(right) == k - 1: return pivot elif len(right) > k - 1: return quick_select(right, k) else: return quick_select(left, k - len(right) - 1) ``` 4. 设计一个算法,找出一个无序整数数组出现次数超过一半的数。 解答:可以使用摩尔投票法,遍历整个数组,维护一个候选数和计数器,如果当前元素等于候选数,则计数器加1;否则计数器减1。如果计数器归零,则将当前元素作为候选数。最后再遍历一遍数组,统计候选数的出现次数,如果出现次数超过一半,则返回该候选数。具体实现如下: ```python def majority_element(arr): if not arr: return None candidate = None count = 0 for num in arr: if count == 0: candidate = num count += (1 if num == candidate else -1) if arr.count(candidate) > len(arr) // 2: return candidate else: return None ``` 5. 设计一个算法,找出一个整数数组的两个元素,使它们的和等于一个给定的数。 解答:可以使用哈希表,遍历整个数组,对于每个元素,如果它的补数已经在哈希表,则返回它们的下标;否则将该元素加入哈希表。具体实现如下: ```python def two_sum(arr, target): if not arr: return None table = {} for i, num in enumerate(arr): complement = target - num if complement in table: return (table[complement], i) else: table[num] = i return None ``` 希望这些答案能够帮助你解决算法设计与分析第四章的部分习题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值