应用分治与递归的算法求循环赛问题。

设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:⑴每个选手必须与其他n-1个选手各赛一次;⑵每个选手一天只能赛一次;⑶循环赛一共进行n-1天。按此要求可将比赛日程表设计-成有n行和n-l列的一个表。在表中第i行和第j列处填入第i个选手在第j天所遇到的选手。用分治法编写为该循环赛设计一张比赛日程表的算法并运行实现、对复杂度进行分析。

算法思想:按分治策略,我们可以将所有选手对分为两组,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用这种一分为二的策略对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了

代码思路:使用vector初始化二维数组,赋初值为1,遍历第一列为运动员编号(以4名运动员为例)

目前我们可以画出一种结果

可以看出左上角与右下角的数字是对应的,左下角与右上角的数字也是对应的,但是我们可以再细分

那么就是第一列第一行的数等于第二列等于第二行的数,第二列第一行的数等于第二行第一列的数。用代码表示为

array[1][1] = array[0][0];
array[0][1] = array[1][0];

因为运动员的数量一直是2的倍数,那么我们循环的过程就可以变成:

for (int i = 0; i < num; ++i) {
        for (int j = 0; j < num; ++j) {
            cout << array[i][j] << " ";
        }
        cout << endl;
}

 共有num行 num列 ,那么当num = 1时 他只循环一次,所以我们用来赋值的方法也可以是

for (int i = 0; i < num; ++i) {
        for (int j = 0; j < num; ++j) {
            //右下角等于左上角
            array[i + num][j + num] = array[i][j];
            //右上角等于左下角
            array[i][j + num] = array[i+ num][j];
        }
    }

 现在是对于两个运动员的可以这样做,那么我们可以采用分治的思想,将8个运动员分成4个运动员,再将4个运动员分成2个运动员就可以这样做,那么我们就需要使用递归的思想,上述讨论的是num = 1的情况,那么递归的时候就要将num一直改变。

下述是C++代码(只出现了cpp的文件,头文件并没有出现,需要自行修改)

//
// Created by yh on 2023/4/3.
//
#include "experiment_one.h"

int n;

void divide_and_conquer_algorithm() {
    //输入k值 确定运动员的人数 n = 2 ^ k
    cout << "请输入k值(n = 2 ^ k):";
    int k;
    cin >> k;
    //则确定n的数量 即运动员的数量
    n = (int) pow(2, k);
    //用vector 进行初始化二维数组
    vector<vector<int> > array(n, vector<int>(n, 1));
    //将第一列初始化为运动员编号
    for (int i = 0; i < array.size(); ++i) {
        array[i][0] = i + 1;
    }
    //打印
    print_array(array);
    cout << "------------" << endl;
    //开始分治
    my_partition(array, 0, 0, n);
    //打印
    print_array(array);
}

void my_partition(vector<vector<int>> &array, int row, int col, int num) {
    //判断人数
    if (num == 1) {
        return;
    }
    //分一半
    num >>= 1;
    //左上
    my_partition(array, row, col, num);
    //左下
    my_partition(array, row + num, col, num);
    /**
    * 如果第一轮是4人 那么num现在是 2人
    * 1 2 3 4
    * 2 1 4 3
    * 3 4 1 2
    * 4 3 2 1
    * 左上角对应的右下角
    * 已经把第一列的初始化了
    */
    //循环 num * num次
    //现在一个人对一个人
    for (int i = 0; i < num; ++i) {
        for (int j = 0; j < num; ++j) {
            //右下角等于左上角                               1         1
            array[i + row + num][j + col + num] = array[i + row][j + col];
            //右上角等于左下角
            array[i + row][j + col + num] = array[i + row + num][j + col];
        }
    }

}

void print_array(const vector<vector<int>> &array) {
    for (const auto &i: array) {
        for (int j: i) {
            cout << j << " ";
        }
        cout << endl;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值