題目:
設有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 }