[算法]循环赛日程表

问题描述:

设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:

  1. 每个选手必须与其他n-1个选手各赛一次;
  2. 每个选手一天只能参赛一次;
  3. 循环赛在n-1天内结束。

请按此要求将比赛日程表设计成有n行和n-1列的一个表。在表中的第i行,第j列处填入第i个选手在第j天所遇到的选手。其中1≤i≤n,1≤j≤n-1。

-------------------------------------------------------------------------

解答:

这个算法被划分到了分治算法的例子,的确它包含分治算法的意思,但是如果从构建规则出发,而不是从分治思想出发,我怎么感觉想起来更不绕弯呢!

其实这个表的构建很容易。首先有个数组T,n行n列,第一列第一行填入数字1,初始就是这个样子的。

1

 

此时k=0,由它向下扩展,向右扩展,向右下扩展就变成了k=1的情况,即由一行一列变成二行而列,如何扩展呢?

向下:原始值(左上角)加1(k)向下搬

右上:把刚才填充上的左下的搬上去

右下:把原来的,左上的搬下去。

1

2

 

2

1

 
   

按照这个规律,当K=2的时候,应该是这个样子的

1

2

3

4

 

2

1

4

3

 

3

4

1

2

 

4

3

2

1

 
     

当K=3的时候,应该是这个样子的

1

2

3

4

5

6

7

8

2

1

4

3

6

5

8

7

3

4

1

2

7

8

6

6

4

3

2

1

8

7

5

5

5

6

7

8

1

2

3

4

6

5

8

7

2

1

4

3

7

8

5

6

3

4

1

2

8

7

6

5

4

3

2

1

 

把第一列去掉就是我们想要的8个运动员的比赛日程表。

想通了,代码就非常容易了。

/// <summary>
        /// 生成比赛日程表
        /// </summary>
        /// <param name="k">运动员数为2的n次方</param>
        public void GenerateTable(int n)
        {
            int N=(int)Math.Pow(2,n);
            int[,] T=new int[N,N];
            T[0, 0] = 1;
            for (int k = 0; k < n; k++)
            {
                int end=(int)Math.Pow(2,k)-1;  //左上小方块结束的行和列
                int end2 = (int)Math.Pow(2,k+1) - 1; //本次填充结束的行和列
                int baseNum = (int)Math.Pow(2,k); 
                //左下填充
                for (int i = end + 1; i <= end2; i++)
                {
                    for (int j = 0; j <= end; j++)
                    {
                        T[i, j] = T[i - baseNum, j] + baseNum;
                    }
                }
                //右上填充
                for (int i = 0; i <= end; i++)
                {
                    for (int j = end + 1; j <= end2; j++)
                    {
                        T[i, j] = T[i + baseNum, j - baseNum];
                    }
                }
                //右下填充
                for (int i = end + 1; i <= end2; i++)
                {
                    for (int j = end + 1; j <= end2; j++)
                    {
                        T[i,j]=T[i-baseNum,j-baseNum];
                    }
                }
            }
            //output
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < N; i++)
            {
                for (int j = 1; j < N; j++)
                {
                    sb.Append(T[i,j]+" ");
                }
                sb.Append("\n");
            }
            Console.WriteLine(sb);
            Console.ReadKey();

        }

  

转载于:https://www.cnblogs.com/orchid/p/3275747.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值