算法之循环赛日程表

循环赛日程表

一.问题描叙

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

(1).每个选手必须与其他n-1个选手各赛一场

(2).每个选手一天只能赛一次

(3).循环赛一共进行n-1天

二.问题分析

按此要求可将比赛日程表设计成n行n-1列的表,在表中第 i 行和第j 列处填入第 i 个选手在第 j 天所遇到的对手。

例如,当选手的人数为8人时,其比赛日程表如下图

算法分析:按分治策略,我们可以将所有的选手分为两半,则n个选手的比赛日程表可以通过n/2个选手的比赛日程表来决定。递归地用这种一分为二的策略对选手进行划分,直到只剩下两个选手时,比赛日程表的制定就变得很简单。这时只要让这两个选手进行比赛就可以了。如上图,所列出的正方形表是8个选手的比赛日程表。其中左上角与左下角的两小块分别为选手1至选手4和选手5至选手8前3天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,又将左下角小块中的所有数字按其相对位置抄到右上角,这样我们就分别安排好了选手1至选手4和选手5至选手8在后4天的比赛日程。依此思想容易将这个比赛日程表推广到具有任意多个选手的情形。

算法实现步骤:

(1)当k=1时,即人数为2人,此情况为最简单的情况

此时表为

1  2

2  1

(2)当k=2时,人数为4人,循环表为

1  2  3  4

2  1  4  3

3  4  1  2  

4  3  2  1

(3)当k=3时,人数为8人,此时循环表为

1  2  3  4  5  6  7  8

2  1  4  3  6  5  8  7

3  4  1  2  7  8  5  6

4  3  2  1  8  7  6  5

5  6  7  8  1  2  3  4

6  5  8  7  2  1  4  3

7  8  5  6  3  4  1  2

8  7  6  5  4  3  2  1

以此类推,我们不难发现,我们可以用分治的方法实现,现自顶向下分解,直到分解到最简单的情况,即人数为2人,这时就可以两两比赛,表的填充为对角填充的方式,然后再自底向上填充表格,具体的看上面的k=1,k=2,k=3时形成的循环表就很好理解了。

三.源代码展示

 1 #include<stdio.h>
 2 #include<math.h>
 3 #define N 50
 4 void GameTable(int k,int array[][N]);
 5 void print(int k,int array[][N]);         //输出二维数组
 6 main()
 7 {
 8     int k;
 9     int array[N][N];
10     printf("\t\t****************************************\n");
11     printf("\t\t**\t\t循环赛日程表          **\n");
12     printf("\t\t****************************************\n\n");
13     printf("设参赛选手的人数为n(n=2^k),请输入k 的值:");
14     do
15     {
16          scanf("%d",&k);
17         if(k!=0)
18         {
19             GameTable(k,array);
20             print(k,array);
21         }
22         else
23           printf("您输入的数据有误,请重新输入");
24     }while(k!=0);
25
26 }
27 void GameTable(int k,int array[][N])//数组下标从1开始
28 {
29     int i,j,s,t;
30     int n=1;
31     for(i=1;i<=k;i++)
32         n*=2;                       //求总人数
33     for(i=1;i<=n;i++)
34         array[1][i]=i;                  //第一行排1-8
35     int m=1;                          //用来控制每一次填表时i行j列的起始填充位置
36     for(s=1;s<=k;s++)                 //s指对称赋值的总循环次数,即分成几大步进行制作日程表
37     {
38         n=n/2;
39         for(t=1;t<=n;t++)              //t指明内部对称赋值的循环次数
40             for(i=m+1;i<=2*m;i++)
41                 for(j=m+1;j<=2*m;j++)
42                 {
43                     array[i][j+(t-1)*m*2]=array[i-m][j+(t-1)*m*2-m];       //右上角等于左上角的值
44                     array[i][j+(t-1)*m*2-m]=array[i-m][j+(t-1)*m*2];       //左下角等于右上角的值
45                 }
46         m*=2;
47     }
48
49 }
50 void print(int k,int array[][N])
51 {
52     int i,j;
53     int num=pow(2,k);
54     printf("%d人的循环赛日程表如下\n",num);
55     for(i=1;i<=num;i++)                           //输出二维数组
56     {
57         for(j=1;j<=num;j++)
58         {
59             printf("%d\t",array[i][j]);
60         }
61          printf("\n");
62     }
63 } 

四.程序结果展示

时间: 2024-10-21 20:34:37

算法之循环赛日程表的相关文章

棋盘覆盖问题&amp;循环赛日程表问题

---恢复内容开始--- 简单的分治,曾经看了好久想了好久也不会的随着时间变成最简单的题,由于刘汝佳书上说的不多,网上找到的又总是一个湖南OJ上的题(看都不愿意看)所以我还是仅说一下思想吧. 棋盘覆盖问题: 我觉得核心问题是在找不到特殊方格是假设了3个方格做特殊方格使分治继续. 循环赛日程表相对就脑残多了,关键是找到规律,然后分治问题到只有2*2的表格,(已经打好了),然后一点点按照规律打印其他小单位. 由于这题找到了原题,(并且很简单)我就把自己代码复制一下,棋盘覆盖问题是在网上找的,可以用来

循环赛日程表(Java实现)

1 /** 2 * 循环赛日程表:有n = 2^k个运动员要进行网球循环赛 3 * 赛程表满足: 4 * 每个选手必须与其他n-1个选手各赛一次 5 * 每个选手一天只能参赛一次 6 * 循环赛在n-1天内结束 7 * 8 * 解题思路: 9 * 将比赛日程表设计成一个n行和n-1列的表,第i行,第j列分别填入第i个选手在第j天所遇到的选手 10 * 栗子: 11 * 4个选手 12 * --------- 13 * |1|2|3|4| 14 * --------- 15 * |2|1|4|3|

循环赛日程表(非递归)

#include<iostream> #include<vector> #include<iterator> #include<algorithm> using namespace std; /* *循环赛日程表(非递归) */ void Copy(int **map,int sr,int sl,int dr,int dl,int k) { for (int i = 0; i < k; i++) { for (int j = 0; j < k;

循环赛日程表(递归法)

#include<iostream> #include<vector> #include<iterator> #include<algorithm> using namespace std; /* *循环赛日程表(递归法) */ void Copy(int **map,int sr,int sl,int dr,int dl,int k) { for (int i = 0; i < k; i++) { for (int j = 0; j < k;

循环赛日程表 分治法

循环赛日程表 分治法 采用分治法, 逐步产生结果, 将 左上角的数字,拷贝到 右下角, 右上角的数字,拷贝到 左下角. 本程序以偶数计算,如果是奇数的话,那么就多增加一个,做轮空处理. // 采用分治法 #include <iostream> #include <cstdio> using namespace std; const int M = 1<<10; int a[M][M]; void getTable(int k) // 2^k { int n = 1<

循环赛日程表(用来说明算法导论上的题目!!)

设有n=2k个选手参加比赛,要求设计一个满足一下要求的比赛日程表: (1)每个选手必须与其他的n-1个选手个比赛一次: (2)每个选手每天只能赛一次 . 按此要求可以把比赛日程表设计成一个n行n-1列的二维表,其中第i行第j列表示第i个选手在 第j天比赛的选手. 代码:(分治策略) 1 #include<stdio.h> 2 #include<math.h> 3 4 void gametable(int k) 5 { 6 int a[100][100]; 7 int n,temp,

循环赛日程表

[题目] 设计一个满足以下要求的比赛日程表:(1) 每个选手必须与其他n-1个选手各赛一次:(2) 每个选手一天只能赛一次:(3) 循环赛一共进行n-1天. 传统方法:将比赛日程表设计为:n行 n-1列的表(i,j)表示:第i个选手在第j 天 遇到的选手 [算法解析] 按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定. 递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单. 这时只要让这2个选手进行比赛就可以了. [代码]

【动态规划】循环赛日程表

1 #include <stdio.h> 2 #include <stdlib.h> 3 int a[10000][10000]; 4 void huan(int row,int len) 5 { 6 int i,j; 7 for(i=0; i<len/2; i++) 8 { 9 for(j=0; j<len/2; j++) 10 { 11 a[row+i+len/2][j+len/2] = a[row+i][j]; 12 } 13 } 14 for(i=0; i<

循环赛日程表问题

#include<stdio.h> #include<math.h> void gametable(int k) { int a[100][100]; int n,temp,i,j,p,t; n=2;//k=0两个参赛选手日程可以直接求得 a[1][1]=1;a[1][2]=2; a[2][1]=2;a[2][2]=1; for(t=1;t<k;t++)//迭代处理,依次处理2^n....2^k个选手的比赛日程 { temp=n;n=n*2;//填左下角元素 for(i=te