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< int half = size/2; //左下角利用初始化最小模块赋值 for(int i=0;i for (int j=0;j dp[i+half][j] = dp[i][j]+half; } } //右上角赋值 for(int i=0;i for (int j=0;j dp[i][j+half] = dp[i+half][j]; } } //右下角赋值 for(int i=0;i for (int j=0;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--;//恰好为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< int half = size/2; //左下角利用初始化最小模块赋值 for(int i=0;i for (int j=0;j dp[i+half][j] = dp[i][j]+half; } } //右上角赋值 for(int i=0;i for (int j=0;j dp[i][j+half] = dp[i+half][j]; } } //右下角赋值 for(int i=0;i for (int j=0;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(); } } }