n支队伍循环赛安排(附完整代码)

问题分析

循环赛问题属于分治思想的经典问题,主要先对最小模块初始化,通过递归,分治进行处理得到最终的赛程表。对于队伍数目并不是刚好为2的整数幂的情况,也做了相应的处理,但是并不是所有情况均可完美解决。

算法解析

①赛程表求解:分治思想
1)首先对左上角第一个最小模块进行初始化

		if(index==0){
            dp[0][0]=1;
            dp[0][1]=2;
            dp[1][1]=1;
            dp[1][0]=2;
            index++;
            arrange(teamNum,index);
        }

2)开始二分法递归依次处理左下角,右下角,右上角。第一轮以初始化最小模块为基本单元,首先将该模块左下角,右下角,右上角的同规模单元填充赋值。填充完毕后以四块单元组成的区域为新的最小模块,即下一轮递归认为左上角的模块已经完成装填,继续递归调用,直到index二分的指数下的以二为底的整数幂大于队伍数目,结束递归。

	 else{
            int size=0x1<<index;
            int half = size/2;
            //左下角利用初始化最小模块赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i+half][j] = dp[i][j]+half;
                }
            }
            //右上角赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i][j+half] = dp[i+half][j];
                }
            }
            //右下角赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i+half][j+half] = dp[i][j];
                }
            }
            if(size>=teamNum){
                return;
            }
            //每次递归完成后默认完成了一个左上角模块的装填
            arrange(teamNum,index+1);
        }

②将结果处理成n支队伍数目:如果是队伍匹配到大于队伍总数目的队号需要安排轮空。

 public void print(){
        for (int i=1;i< (0x1<< index);i++){//控制列号
            System.out.println("第"+i+"天赛程:");
            for(int j=0;j< teamNum;j++){
                if(dp[i][j]<=teamNum){
                    System.out.print(dp[j][0]+"对阵"+dp[i][j]+" ");
                }
                else{
                    System.out.print(dp[j][0]+"轮空 ");
                }
            }
            System.out.println();
        }
    }

③结果展示
在这里插入图片描述

完整代码

package com.algorithm.day1;

import java.util.Scanner;

public class SportSchedule {
    int [][] dp =new int[100][100];
    int index=0;//以二为底的幂指数
    int teamNum=0;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        SportSchedule sportSchedule = new SportSchedule();
        sportSchedule.teamNum = scanner.nextInt();
        int tmp = sportSchedule.teamNum;
        while(tmp>0){
            tmp=tmp>>1;
            sportSchedule.index++;//位运算计算指数index
        }
        if ((0x1<<sportSchedule.index)/ sportSchedule.teamNum==2){
            sportSchedule.index--;//恰好为2的整数幂时,index需要减一
        }
        sportSchedule.arrange(sportSchedule.teamNum, 0);
        sportSchedule.print();
    }
    public void arrange(int teamNum,int index){
        if(index==0){
            dp[0][0]=1;
            dp[0][1]=2;
            dp[1][1]=1;
            dp[1][0]=2;
            index++;
            arrange(teamNum,index);
        }
        else{
            int size=0x1<<index;
            int half = size/2;
            //左下角利用初始化最小模块赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i+half][j] = dp[i][j]+half;
                }
            }
            //右上角赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i][j+half] = dp[i+half][j];
                }
            }
            //右下角赋值
            for(int i=0;i<half;i++){
                for (int j=0;j<half;j++){
                    dp[i+half][j+half] = dp[i][j];
                }
            }
            if(size>=teamNum){
                return;
            }
            //每次递归完成后默认完成了一个左上角模块的装填
            arrange(teamNum,index+1);
        }
    }

    public void print(){
        for (int i=1;i< (0x1<< index);i++){//控制列号
            System.out.println("第"+i+"天赛程:");
            for(int j=0;j< teamNum;j++){
                if(dp[i][j]<=teamNum){
                    System.out.print(dp[j][0]+"对阵"+dp[i][j]+" ");
                }
                else{
                    System.out.print(dp[j][0]+"轮空 ");
                }
            }
            System.out.println();
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

freezing?

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

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

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

打赏作者

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

抵扣说明:

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

余额充值