最近在学习算法分析与设计这门课时,遇到了循环赛日程表问题。我感觉课本上的方法并不是很好(浪费空间而又不好理解),而网上流传的代码也基本和课本上类似,于是我决定用自己的方式来实现这个算法。

目录

问题描述

设有n=2^k个运动员要进行羽毛球循环赛,现要设计一个满足以下要求的比赛日程表:

每个选手必须与其他n-1个选手各赛一次;

每个选手一天只能赛一次;

循环赛一共需要进行n-1天

由于n=2^k,显然n为偶数。

算法思路

根据分治法的思想,递归地将问题一分为二,直到只剩下两个人比赛,最后在将这些问题合并起来,这样问题就变得十分简单。日程表的制定过程中存在一定的规律,即第i行第j列表示第i个选手在第j天所遇到的选手。这样算法就很容易实现了。

2^1个选手的比赛日程表

当问题规模为2^1时,此时问题最为简单,只需要将每个选手复制到对角线位置即可。

2^2个选手的比赛日程表

当问题规模为2^2时,将问题划分为2个规模为2^1的子问题,先解决子问题,然后在将问题规模为2^1的子问题看作一个整体,并复制到对角线位置,这时即可得到总问题的解。

2^3个选手的比赛日程表

与上面类似,先将问题划分为4个问题规模为2^1的子问题,分别解决后,再将这些子问题看作一个整体分别复制到对角线处,即可得到两个问题规模为2^2的子问题,最后再将规模变大了的子问题分别复制到对角线处,即可得到总问题的解。

……

算法实现

这里我只对代码的关键部分做简要的解释,即下面部分:

#define N 3

...

int sche = pow(2.0, N); // divide the problem to pow(2, k) subproblems

...

for (int j = 0; j < N; j++)

{

// gets the size of the problem,

// every loop the problem will triple

bw = pow(2.0, j);

for (int r = 0; r < bw; r++)

{

for (int c = 0; c < sche; c++)

{

// uses round to get the index of problem block

bid = (c + bw) / bw;

c_offset = pow(-1.0, bid + 1) * bw;

r_offset = bw;

arr[r + r_offset][c + c_offset] = arr[r][c];

}

}

}

代码中使用了三层循环,最外层的循环控制问题的规模,即当j=0时,问题规模最小,即前面介绍的规模为2^1的问题;当j=1时,问题规模为2^2;当j=2时,问题规模为2^3……以此类推。这部分可以最能体现分治法的特点,将大问题划分为小问题。

第二层与第三层分别控制元素的行和列,这两层循环主要负责解决不同规模的问题,简单地说就是分别将不同规模的问题块复制到对角线的位置。

为了完成这个看似简单的过程,我们首先需要找一下规律(由于2^k必为偶数,所以n为奇数):

子问题规模为2^1(j=0)时,

a[0][0]–>a[1][1]

a[0][1]–>a[1][0]

a[0][2]–>a[1][3]

a[0][3]–>a[1][2]

a[0][n-1]–>a[0+2^0][(n-1)+2^0]

a[0][n]–>a[0+2^0][n-2^0]

也就是说当元素的ID(ID=列号+1)为奇数时,移动到右下角(横纵坐标分别加2^0);当列ID为偶数时,移动到左下角(横坐标减2^0,纵坐标加2^0)。

子问题规模为2^2(j=1)时,

a[0][0]–>a[2][2]

a[0][1]–>a[2][3]

a[0][2]–>a[2][0]

a[0][3]–>a[2][1]

a[0][n-3]–>a[0][(n-3)+2^1]

a[0][n-2]–>a[0][(n-2)+2^1]

a[0][n-1]–>a[0+2^1][(n-1)-2^1]

a[0][n]–>a[0+2^1][n-2^1]

现在规律就没有那么明显了,但是如果我们按照整块来找规律的话,那么规律就相对容易找一些。你可以这样划分块:即按照2x2的块来划分,每个块都对应一个ID,同样当ID为奇数时,移动到右下角(横纵坐标分别加2^1);当ID为偶数时,移动到左下角(横坐标减2^1,纵坐标加2^1)。

NOTE:其实问题规模为2^1时,块的大小为1x1。

当子问题规模为2^3(j=2)时,

a[0][0]–>a[4][4]

a[0][2]–>a[4][6]

a[0][4]–>a[4][0]

a[0][7]–>a[4][3]

很显然,这里块的大小为4x4,移动的方法我这里也就不在赘述了。

综上所述,块的大小分别是2^0x2^0,2^1x2^1,2^2x2^x,…,2^nx2^n,每次都按照块来进行对角线复制,这时规律就显而易见了,所以r(行ID)的最大值就是块的宽度。但是还有一个比较棘手的问题——如何将数组中的每个元素与块的ID一一映射呢?我经过一番思考终于找到了规律:

BLOCK_ID = (COL_ID + BLOCK_WIDTH)/BLOCK_WIDTH

原代码中是这样写的:

bid = (c + bw) / bw;

其实上面这个式子的灵感来源于我最近在学的CUDA编程中一个经典例子,在那里我学到了圆整(rounding)这个概念(实际上很早就接触过这个东西,只是当时并没有这个概念),圆整的方式有很多,常见的就有向上圆整(round up)和向下圆整(round down),如果你对圆整感兴趣,可以参考相关词条rounding。在我的这个式子中就用到了向上取整的方式,很容易理解,这里就不在赘述了。

到这里,所有的问题都解决了。

NOTE:细心的朋友可能会注意到,源码中是按行复制的。这与图中按列复制并不一致,但原理是一样的。

你可以在这里下载源码。

python实现循环赛日程表问题的算法_循环赛日程表问题相关推荐

  1. python实现循环赛日程表问题的算法_循环赛日程表的分治算法实现实验报告gxl.doc...

    循环赛日程表的分治算法实现实验报告gxl PAGE PAGE 2 深 圳 大 学 实 验 报 告 课程名称: 算法设计与分析 实验项目名称: 分治算法 --矩阵相乘的Strassen算法及时间复杂性分 ...

  2. python实现循环赛日程表问题的算法_循环赛日程表的分治算法实现实验报告_gxl.doc...

    循环赛日程表的分治算法实现实验报告_gxl 深 圳 大 学 实 验 报 告 课程名称: 算法设计与分析 实验项目名称: 分治算法 --矩阵相乘的Strassen算法及时间复杂性分析 或--循环赛日程表 ...

  3. python卷积神经网络cnn的训练算法_【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理...

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  4. python 抽奖 完全公平的随机数算法_抽奖 随机数

    最近修改了网站的抽奖算法,使得抽奖看起来更加『公平』,为此我整理了下,谈谈在抽奖系统设计中的『坑』. 抽奖分为两种: 知道总人数 不知道总人数 举栗子 1. 已知人数 14 个奖品分给 500 个人: ...

  5. 分治算法解循环赛日程表问题

    • 问题描述:n=2^k个运动员进行"地表最强16人"循环赛,日程满足:   每个选手必须与其他n-1个选手比赛一次:   每个选手一天只能赛一次:   循环赛一共进行n-1天. ...

  6. python序列模式的关联算法_关联算法

    以下内容来自刘建平Pinard-博客园的学习笔记,总结如下: 1 Apriori算法原理总结 Apriori算法是常用的用于挖掘出数据关联规则的算法,它用来找出数据值中频繁出现的数据集合,找出这些集合 ...

  7. 递归与分治策略算法之循环赛日程表

    递归与分治策略算法之循环赛日程表 1.先简单的来介绍一下分治策略的思想 分治策略的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,分解出来的子问题与原问题相同,并且相互独立.通过递归去解决子 ...

  8. 用python做算法_自己用python写的螺旋矩阵生成算法

    自己用python写的螺旋矩阵生成算法 如果输入6,可以生成如下矩阵: 1 20 19 18 17 16 2 21 32 31 30 15 3 22 33 36 29 14 4 23 34 35 28 ...

  9. matlab 随机森林算法_(六)如何利用Python从头开始实现随机森林算法

    博客地址:https://blog.csdn.net/CoderPai/article/details/96499505 点击阅读原文,更好的阅读体验 CoderPai 是一个专注于人工智能在量化交易 ...

  10. python颜色识别算法_纯Python编写K-means算法,提取图片中的主体颜色

    在文章 今天我用Python手写了一个K-means算法,来完成同样的功能. 聚类是数据挖掘中一种非常重要的学习流派,指将未标注的样本数据中相似的分为同一类,正所谓"物以类聚,人以群分&qu ...

最新文章

  1. Microbiome:HiSeq平台16S扩增子超高通量测序文库构建方法
  2. 百度推送 android7.1,【SDK版本更新】Android SDK 5.7.1
  3. Linux下安装redis并使用RedisDesktopManager连接
  4. Sklearn(v3)——朴素贝叶斯(2)
  5. 直播原理----协议
  6. 程序员修神之路--分布式系统使用网关到底是好还是坏?
  7. Codeforces Round #653 (Div. 3)
  8. 工作135:引用当前组件下面的方法是混入
  9. 社区内放自助打印机,赚钱吗?
  10. 安徽工程大学大学计算机基础,安徽工程大学.pdf
  11. 实现ios常见菜单效果的思路
  12. 为什么要使用线阵相机?
  13. 华为防火墙查看日志命令_华为USG防火墙运维命令大全
  14. AngularJS入门
  15. 【杂览】01:缘分美丽的邂逅
  16. 2022国内TMS运输管理系统排行榜
  17. 直播美颜SDK从技术层面如何自行实现
  18. 搜索引擎收录、抓取、排序页面的原理简析
  19. trex刷固件_西數硬盘维修软件TREX指令使用教程.doc
  20. Appium-Get Orientation(获取定位)

热门文章

  1. 计算机软考深圳积分,2020年软考证书能为深圳积分入户加分吗?
  2. 开调查公司创业,他的公司营业额达80万
  3. 3.3 高斯法求逆矩阵
  4. BI财务分析 – 反映盈利水平利润占比的指标如何分析(上)
  5. 皮尔兹777301安全继电器
  6. 第四届中国区块链开发大赛初评公布 超级链战队多个作品进入复赛
  7. 基于SSM的Web网页聊天室系统
  8. 中国大学生学习与发展追踪研究(2007年至今)与中国综合社会调查(2003-2017年)与中国社会状况综合调查(2006-2019年)
  9. html的实习报告,HTML实习报告
  10. 如何挑选微信第三方开发商