分治法设计比赛日程表

问题描述

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

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

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

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

算法思想

按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。

以下是思考的草稿图(有些乱但应该不影响看😋

094da00ddecf4b318b1b3f77406e61ab.png

算法设计

void GetTable(int k){

  1. 给出k=1时的二维数组,作为迭代的初始值;
  2. 根据二维数组右下角=左上角、右上角=左下角、左下角的元素值为左上角相应位置元素值加2^(k-1)的关系,自下而上地将k=n时的数组进行填充;
  3. 输出生成的二维数组即为所求比赛日程表。

}

算法分析

  1. 算法思想:按照分治策略,将所有参赛的选手分为两部分,n=2^k个选手的比赛日程表就可以通过为n/2=2^(k-1)个选手设计的比赛日程表来决定。递归地进行分割直到只剩下2个选手。
  2. 数组关系简述:求解的过程是自底向上的迭代过程,通过对k=1、2、3时二维数组的分析,可以得到二维数组右下角=左上角、右上角=左下角、左下角的元素值为左上角相应位置元素值加2^(k-1)的关系,进而通过循环实现题目需求。
  3. 时间复杂度:当n=1时,代码不需要进行循环,此时时间复杂度为O(1);当n>1时,外循环t从2到k,eq?k%3D%5Clog_%7B2%7Dn,内循环从m+1(相当于n+1)到n(相当于2n),执行次数为(n-1),其余三个并列的for循环均执行(n-1)次,可得时间复杂度为eq?O%28n%5Clog_%7B2%7Dn%29,即eq?O%28n%5Clog_%7B%7Dn%29。综上,时间复杂度为:

eq?T%28n%29%3D%5Cleft%5C%7B%5Cbegin%7Bmatrix%7D%20O%281%29%2Cn%3D1%20%5C%5C%20O%28n%5Clog_%7B%7Dn%29%20%2Cn%3E1%20%5Cend%7Bmatrix%7D%5Cright.

完整代码

#include<iostream>
using namespace std;


void GetTable(int k){
	
	int a[600][600];		//用二维数组表示比赛日程表 
    int i,j,n,t,m;			//i:行数;j:列数;n:选手数目;t:循环量;m:已经安排的选手个数
    
    n=2;		//n从k=1开始
    a[1][1]=1;
	a[1][2]=2;
    a[2][1]=2;
	a[2][2]=1;				//只有两位选手时的二维数组 
	
    for(t=2;t<=k;t++){		//对2^t位选手安排日程表 
    	m=n;				//将已经建立数组的m位选手存储 
    	n=n*2;				//当前所有选手数
		for(i=m+1;i<=n;i++){		//对二维数组的左下角进行填写 
			for(j=1;j<=m;j++)
			a[i][j]=a[i-m][j]+m;	//左下角的元素值为左上角相应位置元素值加2^(k-1),即m 
		}
		for(i=1;i<=m;i++){			//填写右上角,由算法设计可知右上角=左下角 
			for(j=m+1;j<=n;j++)
			a[i][j]=a[j][i];		//与左下角同一位置元素对应 
		}
		for(i=m+1;i<=n;i++){		//填写右下角,由算法设计可知右下角=左上角 
			for(j=m+1;j<=n;j++)
			a[i][j]=a[i-m][j-m];	//与左上角同一位置元素对应 
		}
	} 
	
	cout<<"参加比赛的选手共有 "<<n<<" 位"<<endl;
	
    for(i=1;i<=n;i++){		//输出所得的二维数组 
        for(j=1;j<=n;j++){
        	cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main(){
    int k;
    cout<<"请输入k的值(n=2^k):";
    cin>>k;
    
    cout<<"比赛日程表如该二维数组所示:" <<endl;
    if(k!=0){
    	GetTable(k);
	}
	cout<<"其中,第i行第j列表示第i位选手在第j-1天比赛的选手编号(i,j均由下标1算起)。";
	
    return 0;
}

结果演示

a0530e6351464439ac9a48775f2021f8.png

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Issme

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值