循环赛日程表问题

问题描述:       

   设有n=2k(2的k次方)个选手要进行网球循环赛,要求设计一个满足以下要求的比赛日程表:

(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次。

       按此要求,可将比赛日程表设计成一个 n 行n-1列的二维表,其中,第 i 行第 j 列表示和第 i 个选手在第 j 天比赛的选手。

循环赛日程表问题主要使用分治思想,将问题分成2个子问题,子问题再分成子问题,然后分别解决子问题合并子问题的解

递归求解:

        首先初始化第一列。将要解决的问题折半,分成上半部分和下半部分,然后分别求2个子问题的解,依次类推,直到剩余2个队伍,此时在2X2的方格内,交换两支队伍,这样2x2方格部分已解决,然后在4x4内交换,依次类推合并各个子问题的解。

以下图为例n=8分成2个n=4子问题,再分成4个n=2的子问题,然后执行交换函数

递归求解的方向是上下

非递归求解:

        首先初始化第一列。然后从左上角开始,以2为单位交换2x2方格队伍,4x4方格队伍以此类推

非递归求解的方向是从左上角斜着往下



以下是代码:

///**********循环赛日程表问题****************///
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
int a[100][100];                  ///日程表,储存最后的结果
void swap(int x,int y,int size){  ///交换对角的两个区域
    int s = size/2;
    for(int i = x + s; i <= x+size-1; ++i){
        for(int j = 0; j < s; ++j){
            a[i][y+s+j] = a[i-s][y+j];
        }
    }
    for(int i  = x; i <= x+s-1; ++i)
        for(int j = 0; j < s; ++j) a[i][y+s+j] = a[i+s][y+j];

}
void solve1(int x,int y,int size){  ///递归解决
    if(size==2){                   ///边界
        swap(x,y,2);
        return;
    }
    solve1(x,y,size/2);             ///递归解决上半部分
    solve1(x+size/2,y,size/2);      ///递归解决下半部分
    swap(x,y,size);                ///合并结果
}
void solve2(int n){                ///非递归解决
    for(int i = 2; i <= n; i*=2){
        for(int j = 1; j <= n; j+=i){
            swap(j,1,i);
        }
    }
}
void print(int n){                 ///打印结果
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j) printf("%d ",a[i][j]);
        printf("\n");
    }
}
int main()
{
    int n;
    scanf("%d",&n);                ///n只队伍
    for(int i = 1; i <= n; ++i) a[i][1] = i;///初始化第一列
    solve1(1,1,n);                 ///递归
    print(n);
    printf("------------------------------\n");
    solve2(n);                     ///非递归
    print(n);
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值