分治法求循环赛日程表

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

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

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

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

按要求可将比赛日程表设计成有n行和n-1列的一个表。在表中第i行和第j列处填第i个选手在第j天所遇到的选手。用分治法编写为该循环赛设计一张比赛日程表的算法。



题目的分析

采用的是递归的方法,每一次考虑的是n*n的二维数组的内容如何实现比赛。

入口参数采用的是序号和人数,当人数只有2人时直接安排比赛,将2人看作2*2的数组,先看左半部分,依次给左半部分的上下赋值,赋值的依据是根据序号;

然后当人数大于2时继续递归调用函数本身,直到人数为2时执行相关代码后到尾部执行左上角赋值给右下角,左下角赋值给右上角;然后跳出这一层的递归,回到上一层的递归中执行相关代码即可。

注:每次都是先完成2*2的数组数据的填写,再到2^k *2^k扩展。

核心思想:

分治法,将大问题逐渐划分成小问题,然后再合并。

递归处理问题。

巧借下标完成数据最初的赋值。

#include<iostream>

  using namespace std; 
  int a[100][100];
  int n;    //选手的个数  
bool  check(int num){
    if (num == 1)
        return true;
    else
    {
        do
        {
            if (num % 2 == 0)
                num = num / 2;
            else
                return false;
        }
        while (num != 1);
        return true;
    }
 }
 void  roundrob(int k,int m)
 {
      int i,j;
      if(m==2)
 {
         a[k-1][0]=k;    //左上角
         //a[k-1][1]=k+1;
         a[k][0]=k+1;   //左下角
// a[k][1]=k;
 }
 
 else
 {
    roundrob(k,m/2);   //前半部分
roundrob(k+m/2,m/2);   //后
 }
 for(j=k-1;j<k-1+m/2;j++) //数据复制
{
for(i=0;i<m/2;i++)   
{
a[j+m/2][i+m/2]=a[j][i];//左上--》右下
a[j][i+m/2]=a[j+m/2][i];    //左下--》右上
}


     }
      
 }
 int main()
 {
     int n;     
//验证输入的数据是否为2^k
while(1)
{         
        system("cls");
        cout<<"请输入运动员的人数,为2^k个:";
                 cin>>n; 
if(check(n))
{
 roundrob(1,n);
  for(int i = 0; i < n; i++)
  {
for(int j = 0; j < n; j++)
{
cout<< a[i][j] << " ";
}
 cout<<endl;
  } 
}
else
{
cout<<"输入错误,请重新输入!"<<endl;
}
system("pause");
}  
     return 0;
 }
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 C 语言编写的分治法循环赛日程表的代码: ```c #include <stdio.h> #include <stdlib.h> void roundRobin(int n, int **table, int start) { if (n == 1) { table[0][start] = 1; return; } int **newTable = (int **)malloc(n * sizeof(int *)); for (int i = 0; i < n; i++) { newTable[i] = (int *)malloc(n * sizeof(int)); } int m = n / 2; roundRobin(m, newTable, start); for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { table[i][j + m] = newTable[i][j] + m; table[i + m][j] = newTable[i][j] + m; table[i + m][j + m] = newTable[i][j]; } } for (int i = 0; i < n; i++) { for (int j = m; j < n - 1; j++) { int k = (i + j - m + start) % (n - 1); table[i][k] = table[i][j]; table[i][j] = n - 1 + table[i][j]; } } for (int i = 0; i < n; i++) { free(newTable[i]); } free(newTable); } int main() { int n; printf("请输入参赛队伍的数量:"); scanf("%d", &n); int **table = (int **)malloc(n * sizeof(int *)); for (int i = 0; i < n; i++) { table[i] = (int *)malloc(n * sizeof(int)); for (int j = 0; j < n; j++) { table[i][j] = -1; } } roundRobin(n, table, 0); printf("循环赛日程表如下:\n"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (table[i][j] < n - 1) { printf("%d vs %d\t", i + 1, table[i][j] + 1); } } printf("\n"); } for (int i = 0; i < n; i++) { free(table[i]); } free(table); return 0; } ``` 在这个代码中,我们使用分治法来构造循环赛日程表。我们先将所有队伍分成两组,然后递归地构造这两组的循环赛日程表,然后再将它们合并起来得到整个循环赛日程表。具体的合并方法是,对于左上、右上和左下三个子矩阵,将它们的元素加上一个固定的偏移量,然后再将右上和左下矩阵交换,得到一个新的矩阵,然后将这个矩阵的右半部分

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值