循环日程表问题

循环日程表问题

问题描述:

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

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

2.每个选手一天只能参赛一次;

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

按此要求设计一张比赛日程表,该表有 n 行和 n-1 列,第 i j 列为第 i 个选手在第 j 天所遇到的选手。

算法分析:

循环日程表问题方法有很多种,分治是其中一种比较容易理解的方法.按分治策略,将所有的选手分为两半,则 n 个选手的比赛日程表可以通过n/2个选手的比赛日程表来决定。递归地用分治策略将选手进行划分,直到只剩下两个选手时,达到递归边界。这时仅有两个选手进行比赛。当k = 3时,则一共有8个选手进行比赛,先对赛程表的第一行进行1-8的赋值!根据第一行对第二行进行赋值:其中第一块为1号与2号的比赛日程,左上角与左下角的两小块分别为选手1第一天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,又将左下角小块中的所有数字按其相对位置抄到右上角,这样我们就分别安排好了选手1至选手2在第一天的比赛日程.同理后面3块分别为:3与4,5与6,7与8的比赛日程。


根据第一二行对第三四行进行赋值:其中第一块为选手1至选手4的比赛日程,左上角与左下角的两小块分别为选手1,2号,选手3,4号第一天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,又将左下角小块中的所有数字按其相对位置抄到右上角,这样我们就分别安排好了选手1至选手4在前3天的比赛日程.同理后面1块为:选手5至选手8在前3天的比赛日程。


根据前四行对后四行进行赋值:同中一块为选手1至选手8的比赛日程,左上角与左下角的两小块分别为选手1至选手4,选手5至选手6前3天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,又将左下角小块中的所有数字按其相对位置抄到右上角,这样我们就分别安排好了选手1至选手8在前7天的比赛日程.依此思想容易将这个比赛日程表推广到具有任意多个选手的情形.



代码实现:

#include <stdio.h>
#include <iostream>
#include <math.h>
#include <string.h>
#include <algorithm>
using namespace std;

int maps[100][100];

void solve(int k,int n)
{
    int m = 1;///m用来控制每一次填充表格时i和j的起始填充位置
    
    for(int i = 1; i <= n; i++)///对日程表第一行进行初始化
        maps[1][i] = i;
    
    for(int s = 1; s <= k; s++)///控制复制次数
    {
        n /= 2;
        for(int t = 1; t <= n; t++)///控制复制对角块的次数
        {
            for(int i = m + 1; i <= 2 * m; i++)
            {
                for(int j = m + 1; j <= 2 * m; j++)
                {
                    maps[i][j + (t - 1) * m * 2] = maps[i-m][j + (t - 1) * m * 2 - m];///左上角的值复制给右下角
                    maps[i][j + (t - 1) * m * 2 - m] = maps[i-m][j + (t - 1) * m * 2];///右上角的值复制给左下角
                }
            }
        }
        m *= 2;
    }
}

int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        int num, n = 1;
        for(int i = 1; i <= k; i++)
            n *= 2;
        num = n;
        solve(k, n);
        for(int i = 1; i <= num; i++)
        {
            for(int j = 1; j <= num; j++)
                printf("%2d ",maps[i][j]);
            printf("\n");
        }
    }
    return 0;
}



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值