循环赛日程表_分治法
题目:
设有n=2^k个运动员要进行网球循环赛。现要设计一各满足一下要求的比赛日程表:
1、每个选手必须与其他n-1个选手各比赛一次。
2、每个选手一天只能赛一次。
3、循环赛一共进行n-1天。
按照此要求可以将比赛日程表设计成一个n*n的二维表,第一列表示选手,接下来的每一列依次表示将要比赛的每一天选手。下面以8个选手为例:
思路:
按照分治法,可将所有选手进行二分,n个选手的比赛安排可通过n/2个选手的日程表来决定。递归地用这种一分为二的策略对选手进行分割,知道只剩两个选手,日程表显然直接安排即可。
下图为8个选手的比赛日程表:
图1
算法步骤:
1、利用一个for循环初始化选手1的日程安排,即图1中的第一行。
2、根据选手1的日程安排来安排选手2。此刻为最小规模,以相邻的每两天即四个最小单元为一组,例如选手一第一天要跟选手2比赛,那么相应选手2也要跟选手1比赛,所以将图1中的第一行第一列序号抄到第二行第二列,将第一行第二列序号抄到第二行第一列。依次,第3、4列,第5、6列,第7、8列也是。
3、根据选手1、2的日程安排可以按照左上角数据抄到右下角,右上角数据抄到左下角安排出选手3、4的日程。
4、最后根据前四选手,可以将所有人的日程表都安排出来。
下面是java实现完整代码:
1 package competition; 2 3 import java.util.Scanner; 4 5 public class Com { 6 private static Scanner scanner; 7 8 public static void main(String [] args) { 9 int k; //注意,n才是选手的人数,k只是问题要划分的子问题规模数,即n=2^k 10 System.out.println("输入k:"); 11 scanner = new Scanner(System.in); 12 k=scanner.nextInt(); 13 int a[][]=new int[pow(2,k)+1][pow(2,k)+1]; 14 table(k, a); 15 for(int i=1; i<pow(2,k)+1; i++){ 16 for(int j=1; j<pow(2,k); j++){ 17 System.out.print(a[i][j]+" "); 18 } 19 System.out.println(a[i][pow(2,k)]); 20 } 21 } 22 23 static void table(int k, int [][]a){ 24 int n=pow(2,k); 25 for(int i=1; i<=n; i++) a[1][i]=i; 26 int m=1;//定义M为记录每一次填充时i、j的起始填充位置 27 for(int s=1; s<=k; s++){//分治规模 28 n/=2; 29 for(int t=1; t<=n; t++)//t是每一层分治中进行对称的单位的个数 30 for(int i=m+1; i<=2*m; i++)//控制行 31 for(int j=m+1; j<=2*m; j++){//控制列 32 a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];//右下角的值等于左上角的值 33 a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];//左下角的值等于右上角的值 34 } 35 m*=2; 36 } 37 } 38 39 static int pow(int a, int n) {//幂函数 40 int res=1; 41 for(int i=0; i<n; i++) 42 res*=a; 43 return res; 44 } 45 }