分治法——循环赛日程表

来源:互联网 发布:java性能优化 编辑:程序博客网 时间:2024/04/29 15:12

问题描述

设有n=2k个运动员要进行羽毛球循环赛,现要设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其它n-1个选手各赛一次;
(2)每个选手一天只能比赛一次;
(3)循环赛一共需要进行n-1天。
由于n=2^k,显然n为偶数。
按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。
八人循环赛

分治法求解思路

(1)如何分,即如何合理地进行问题的分解?
一分为二
(2)如何治,即如何进行问题的求解?
进行合并
(3)问题的关键——发现循环赛日程表制定过程中存在的规律性。

循环赛日程表算法描述:

Void Round_Robin_Calendar(int k, int **a){     int n=1,i,j,s;       n = 1<<k;       for(i=1;i<=n;i++)  a[1][i]=i;       int m=1;       for(s=1;s<=k;s++)     //问题划分的次数       {    n/=2;             for(int t=1;t<=n;t++)   //每一部分的问题进行单元格的填充                 for(i=m+1;i<=2*m;i++)  //控制行                     for(j=m+1;j<=2*m;j++)   //控制列                      {  a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];                          a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];                       }             m*=2;           }}                        

代码实现

#include <iostream>using namespace std;void Round_Robin_Calendar(int **a,int k);int main(){    int n,k;    cin>>k;    n = 1<<k;    int **a = new int *[n];    for(int i = 1 ; i <= n ; i++)        a[i] = new int[n];    Round_Robin_Calendar(a, k);    for(int i = 1 ; i<= n ; i++)    {        for(int j = 1 ; j <= n ; j++)            cout<<a[i][j]<<" ";        cout<<endl;    }    return 0;}void Round_Robin_Calendar(int **a,int k){    int n;    n = 1<<k;    for(int i = 1 ; i <= n ; i++)   a[1][i] = i;    int m = 1;    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++)                {                    a[i][j+(t-1)*2*m] = a[i-m][j+(t-1)*2*m-m];                    a[i][j+(t-1)*2*m-m] = a[i-m][j+(t-1)*2*m];                }        m *= 2;    }}

测试

测试结果

原创粉丝点击