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

by admin电力供应方案

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();

}

}

}

Read More