原文地址:https://ericpengshuai.github.io/suan-fa/cd0cd01e2295.html

例题
设有N个运动员要进行网球循环赛,设计一个满足以下要求的比赛日程表
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)当n 是偶数,循环赛进行n-1简单天,当n是奇数,循环赛进行n天。

分析

1. 首先考虑简单问题(n = 2^k)
这个我先上一个图大家应该就可以明白:

应该很容易想到分治法,有如下规律:对于任意一个正方形区域(包括4、16……个小方块)左上角和右下角相等,右上角和左下角相等(如果懒得看汉字就直接看上面几种颜色的方块吧
然后这个代码也很容易:

  • 非递归(k是2上面的次数)
void SetTable(int **a, int k)
{//初始化左上角数a[0][0] = 1;a[0][1] = 2;a[1][0] = 2;a[1][1] = 1;//然后分治安排for(int i = 2; i <= k; i++){int len = 1 << i;   //len = 2^iint half = len / 2; //左下角子表就是左上角子表加上halffor(int row = half; row < len; row ++){for(int col = 0; col < half; col ++){a[row][col] = a[row - half][col] + half; }}//右上角子表就是左下角子表for(int row = 0; row < half; row ++){for(int col = half; col < len; col ++){a[row][col] = a[row + half][col - half];}}//右下角子表就是左上角子表for(int row = half; row < len; row ++){for(int col = half; col < len; col ++){a[row][col] = a[row - half][col - half];}}}
}
  • 递归(n是比赛总人数,这里先考虑简单的n = 2^k)
void tourna(int n, int **a)
{if(n == 1){a[0][0] = 1;return;}tourna(n/2, a);copy(n, a);
}
void copy(int n, int **a)
{int m = n / 2;for(int i = 0; i < m; i++){for(int j = 0; j < m; j++){a[i + m][j + m] = a[i][j];  //右下角a[i + m][j] = a[i][j] + m;  //左下角a[i][j + m] = a[i + m][j];  //右上角}}
}

2.衍生到一般的偶数(如果n不是2的次方)
举一个例子(n=6),既然是分治法,按照大的思路,我们把tourna(6, a)问题转换成tourna(3, a)【这里的你们就先看成是上面的tourna函数】,那么问题又来了,n=3怎么解决呢?(自然引出了奇数的问题,那我们直接考虑下面的奇数问题,这里大家可以直接跳到第三种情况看,看完之后回看这一点)
我们可以将6分为(1 2 3)和(4 5 6)我们且看两者单独考虑的赛程:
(1 2 3)(4 5 6)

考虑到(1 2 3)(4 5 6)“1和4”的第四列(第三天),只有一号选手和四号选手没比赛,那就让他们比,同理还有2和5,3和6,推出如下图【左图】:
再来分析【右图】,第一行由于(1 5)(1 6)没比赛,后面就填他们,对应的也有(5 1)(6 2),再看第二行可以是(2 4)(2 6),由于6在第五天和1比赛了,所以应该是先填(2 6)然后(2 4),对应的也有(6 2)(4 2);后面同理。
【其实我感觉这个就是找规律好吗,和分治法有“桃子”关系 】

3.n为奇数
考虑到题目中有n天时间比赛,自然想到n = 4 的情况(看下图)
这个是4个人比赛3天的情况,现在如果只有3个人,那么岂不是正好是3天,我们仅仅需要将其中的4改变为0(看下图),代表选手那天空闲就可

其实对于一般的奇数,我们都可以转换成相应的n + 1,变成偶数再分治求解,最终递归到尽头就是n = 3(然后我们回到第二问)

最终代码整理如下

# include <iostream>
using namespace std;void output(int **a, int n)
{if(n % 2 == 1)  //n为奇数时候的输出for (int i = 0; i < n; i++){for (int j = 0; j < n + 1; j++){if(a[i][j] == n + 1)cout << 0;else  cout << a[i][j];if (j == n)cout << endl;elsecout << ' ';}}else    //n为偶数时候的输出for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){cout << a[i][j];if (j == n - 1)cout << endl;elsecout << ' ';}}
}void copy(int n, int **a)
{int m = n / 2;//cout << m << endl;for(int i = 0; i < m; i++){for(int j = 0; j < m; j++){a[i + m][j + m] = a[i][j];  //右下角a[i + m][j] = a[i][j] + m;  //左下角a[i][j + m] = a[i + m][j];  //右上角}}
}void copyodd(int n, int **a)
{int m = n / 2;int *b = new int[n];for(int i = 0; i < m; i++){b[i] = m + i + 1;   // 4 5 6b[m + i] = b[i];    // 4 5 6}for(int i = 0; i < m; i ++){for(int j = 0; j < m+1; j ++)   //改写左上角和填写右下角{   //这里如果你硬要说什么解释的话,我也说不出啥来,我看来就是找规律if(a[i][j] > m) {a[i][j] = b[i];a[m + i][j] = (b[i] + m) % n;}else a[m +i][j] = a[i][j] + m;}for(int j = 1; j < m; j++)  //填写右上角和对应的右下角{   //这里我当时是把 n = 6作为特例带进去一个一个是试出规律来的a[i][m + j] = b[i + j];a[b[i + j] - 1][m + j] = i + 1;}}
}void makecopy(int n, int **a)
{if((n/2 > 1) && ((n/2)%2 == 1)) copyodd(n, a);else copy(n, a);
}void tourna(int n, int **a)
{if(n == 1){a[0][0] = 1;return;}if(n % 2 == 1) {tourna(n+1, a); //奇数+1变成偶数return;}tourna(n/2, a); //分治makecopy(n, a);
}int main()
{int n;cin >>n;int **a = new int *[2*n];for(int i = 0; i < 2*n; i++)   //分配空间a[i] = new int[2*n];tourna(n, a);output(a, n);for(int i = 0; i < 2*n; i ++)    //delete空间delete []a[i];delete []a;return 0;
}

【分治法】解决循环赛问题(n分为奇数和偶数)相关推荐

  1. 分治法解决循环赛日程表

    分治法解决循环赛日程表 问题描述 设有n=2^k个运动员要进行羽毛球循环赛,现要设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次. (2)每个选手一天只能比赛一次. ( ...

  2. python应用——分治法实现循环赛

    一.要求 用分治法实现循环赛: 一共有n个选手要进行循环赛,请设计一个满足以下要求的比赛日程表: (1)每个选手必须与其他n-1个选手各赛一次: (2)每个选手一天只能赛一次: (3)当n 是偶数,循 ...

  3. 分治法解决最大子数组问题

    分治法解决最大子数组问题 参考文章: (1)分治法解决最大子数组问题 (2)https://www.cnblogs.com/Christal-R/p/Christal_R.html (3)https: ...

  4. 分治法解决组合总和问题(leetcode216)

    nums数组中元素是正整数 大问题转换为小问题 思路和分治法解决组合相同,代码也相似 分治法解决组合问题(递归)_m0_52043808的博客-CSDN博客 只不过递归出口时需要判断组合总和是否为n ...

  5. 分治法解决矩阵乘法问题

    分治法解决矩阵乘法问题 传统for循环: #include<iostream> #include<cstdio> #include <vector> #includ ...

  6. 分治法解决棋盘覆盖问题

    分治法解决棋盘覆盖问题 问题描述: 在一个2k×2k(k≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格.显然,特殊方格在棋盘中出现的位置有4k中情形,因而有4k中不同的棋盘. ...

  7. 分治法解决最小套圈问题

    /*     Copyright    by ZhongMing-Bian     Jan,6,2010   */ /*             分治法解决最小套圈问题                 ...

  8. 【多边形法】解决循环赛问题(n分为奇数和偶数)

    题目在这里就不再赘述,想看的话请参考上一篇[分治法]解决循环赛问题 看到网上关于循环赛问题提出过一种多边形法,感觉这个思路挺简单的,但是看别人代码没看懂,这里我简单分析几种情况然后写出自己理解的代码: ...

  9. 蛮力法与分治法解决最近点对问题-详细分析与C++代码实现

    最近点对问题 最近点对问题の目录 最近点对问题 什么是最近点对问题 代码基本框架 蛮力法及其代码 分治法及其代码 一般分治法遇到的特殊情况 如何优化分治法(6点确定与4点确定解法) 优化后分治法(4点 ...

最新文章

  1. another app is currently holding the yum lock;waiting for it to exit解决
  2. 16、计算机图形学——基于AABB进行光线追踪的加速(下)
  3. 90%的用户都不知道手机内部功能
  4. Android 游戏开发入门
  5. ES 断路器——本质上保护OOM提前抛出异常而已
  6. VB.NET 调用外部程序
  7. SAP Commerce Cloud Product Review 的添加逻辑
  8. python帮助文档中查看内置函数_PYTHON官方文档内置函数整理
  9. apache的mpm工作模式
  10. 《码出高效---java》PDF,有学习java的小伙伴可以看看,阿里巴巴出版的书籍
  11. MySQL数据库 资源
  12. 电脑如设置路由器WiFi外加无线桥接一个副路由器
  13. 营救公主的100种方法
  14. 【web前端面试题整理07】我不理解表现与数据分离
  15. 模拟狗狗的“魔鬼步伐”,比更真还更真
  16. 解决win10系统不能打开.chm类型的文件
  17. Vue项目和Tauri接入Google Analytics谷歌统计流程
  18. android6.0 framwork修改
  19. 李慧芹数据结构代码(顺序表)
  20. 【外文翻译】图像中的傅里叶变换

热门文章

  1. 【linux】linux基础命令-chage详解
  2. 自动seo网站源码_做了利于SEO优化的网站建设,企业的网站就能自动排名靠前?...
  3. 静态网页爬虫教程(2)链接和标题的提取
  4. 微软账号被暂时停用咋办_无需惊慌!微软漏洞数月后再被“预警” 打补丁即可防御...
  5. mt6739方案开发,mt6739基带芯片模块,mt6739资料下载
  6. Justnews主题源码V6.0.1开心版+社交问答插件/附教程
  7. [Python] 人人影视签到脚本
  8. 云服务器信息泄露,云服务器数据泄露
  9. html中汉字代码变成数字代码,Angular.js 实现数字转换汉字实例代码
  10. 噪鹃de“喔啊“悲惨的叫声