一.要求
用分治法实现循环赛:
一共有n个选手要进行循环赛,请设计一个满足以下要求的比赛日程表:
(1)每个选手必须与其他n-1个选手各赛一次;
(2)每个选手一天只能赛一次;
(3)当n 是偶数,循环赛进行n-1天,当n是奇数,循环赛进行n天。
按分治策略,将所有的选手分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。
二.设计思路
总共需要进行n*(n-1)/2场比赛。
当有偶数个选手参加比赛时需要进行n-1天比赛。当有奇数个选手时会出现轮空现象,考虑n+1个选手参加比赛的日程安排,最后将多出来的选手对应的比赛轮空,一共需要进行(n+1)-1天比赛。由此推测,不论参加选手人数为偶数还是奇数,统一处理为偶数考虑。
当n/2为偶数时,通过对子问题矩阵元素的平移即可得到。如下图所示:
当n/2为奇数时,首先将子问题处理为n/2+1的情况,再扩充矩阵,以六名选手为例,如下图所示:
三.程序主体
# coding=utf-8
from numpy import *
def compettion(n,mymat):
if n==2:
mymat[0,0]=1
mymat[0,1]=2
mymat[1,0]=2
mymat[1,1]=1
return#分治迭代至只有2名运动员
# if n%2==1:n+=1#奇数
# t=int(n/2)
if n % 2 == 1:
t=int((n+1)/2)
n+=1
else:
t=int(n/2)
compettion(t,mymat)#分治迭代
#在原先的基础上,扩展矩阵
if n%4==0:#除以2为偶数个运动员
for i in range(int(n/2)):
for j in range(int(n/2)):
thevalue=mymat[i][j]
mymat[i+t][j]=thevalue+t
mymat[i][j+t]=thevalue+t
mymat[i+t][j+t]=thevalue
else:#除以2为奇数个运动员
for i in range(int(n/2)):#截取部分子问题的解
for j in range(int(n/2)+1):
thevalue=mymat[i][j]
if thevalue>t:#子问题中假设出的选手
##用以下两行解决奇数个运动员时矩阵的左半部分
mymat[i+t][j]=i+1##########################下左假设部分恰好为i+1
mymat[i][j] =i+t+1#新假设出的选手处正好为i+t+1
##需要处理矩阵k列开始的右半部分
c=i+t+2#第一个是5
k=int(n/2)+1#第一个是4
while k<n:
if c>n:
c-=t
#if(c==i+t) c++;
mymat[i][k]=c#右
mymat[c-1][k]=i+1#右下
c+=1
k+=1
else:
mymat[i+t][j]=thevalue+t#向下延拓
return mymat
#################################################################
def main():
a =int(input("输入需要进行循环赛的人数:"))
if a%2==0:#运动员人数为偶数
b = zeros([a, a])
compettion(a, b)
else:#运动员人数为奇数
b = zeros([a+1, a+1])
compettion(a+1, b)
for i in range(a+1):
for j in range(a+1):
if b[i][j]>a:
b[i][j]=0
if i ==a:b[i][j]=0
print(b)
if __name__ == '__main__':
main()
四.运行结果
2名选手:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exeC:/Users/Administrator/PycharmProjects/untitled1/xunhuansai.py
输入需要进行循环赛的人数:2
[[ 1. 2.]
[2. 1.]]
Process finished with exit code 0
3名选手:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exeC:/Users/Administrator/PycharmProjects/untitled1/xunhuansai.py
输入需要进行循环赛的人数:3
[[ 1. 2. 3. 0.]
[2. 1. 0. 3.]
[3. 0. 1. 2.]
[0. 0. 0. 0.]]
Process finished with exit code 0
4名选手:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exeC:/Users/Administrator/PycharmProjects/untitled1/xunhuansai.py
输入需要进行循环赛的人数:4
[[ 1. 2. 3. 4.]
[2. 1. 4. 3.]
[3. 4. 1. 2.]
[4. 3. 2. 1.]]
Process finished with exit code 0
5名选手:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exeC:/Users/Administrator/PycharmProjects/untitled1/xunhuansai.py
输入需要进行循环赛的人数:5
[[ 1. 2. 3. 4. 5. 0.]
[2. 1. 5. 3. 0. 4.]
[3. 0. 1. 2. 4. 5.]
[4. 5. 0. 1. 3. 2.]
[5. 4. 2. 0. 1. 3.]
[0. 0. 0. 0. 0. 0.]]
Process finished with exit code 0
6名选手:
C:\Users\Administrator\AppData\Local\Programs\Python\Python36\python.exeC:/Users/Administrator/PycharmProjects/untitled1/xunhuansai.py
输入需要进行循环赛的人数:6
[[ 1. 2. 3. 4. 5. 6.]
[2. 1. 5. 3. 6. 4.]
[3. 6. 1. 2. 4. 5.]
[4. 5. 6. 1. 3. 2.]
[5. 4. 2. 6. 1. 3.]
[6. 3. 4. 5. 2. 1.]]
Process finished with exit code 0
六.结果分析
五名选手及六名选手的结果分别为:
其中第一列为选手序号,第二列为第一天进行比赛的对手,第三列为第二天进行比赛的选手。。。当对手序号为0时,表示当天该选手轮空。
经过对比,5名选手的比赛安排是在6名选手的比赛安排上去掉涉及第6名选手的比赛。运行结果和预先的思路相符。