python应用——分治法实现循环赛

一.要求

用分治法实现循环赛:

一共有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名选手的比赛。运行结果和预先的思路相符。

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值