循环日程表问题(分治)

题意 : 给出 n  = 2k个参赛者,要求每一个参赛者必须与其他 n-1 个选手各赛一次,每个选手一天只能赛一次,循环赛一共进行 n-1 天, 按照此要求设计一张比赛日程表, 使得该表有 n 行和 n-1 列,第 i 行 j 列为第 i 个选手第 j 天遇到的选手。

 

分析 : 刘大爷给出了一个分治的想法,当 k = 2也就是有 4 名选手的时候,左上角可以直接 1 和 2 去比,左下角是左上角每一个数 +2 得到,而右上角和右下角分别是左下角和左上角复制得到,也就是说只要我们得到了左上角,就能得到整张的合法表,一层一层递归下去,然后除了 k == 1 的时候特殊处理一下,其他层就进行复制操作!

 

以下代码自己瞎写的,所以不保证绝对正确

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
int G[maxn][maxn];
int k;
/*
     u m m+1 d
u    1 2  3  4
m    2 1  4  3
m+1  3 4  1  2
d    4 3  2  1
*/
inline void print()
{
    for(int i=1; i<=1<<k; i++){
        for(int j=1; j<=1<<k; j++){
            printf("%d ", G[i][j]);
        }puts("");
    }
}
void DFS(int up, int down, int k)
{
    if(k == 1){
        G[up][1]   = up;
        G[down][1] = down;
        G[up][2]   = down;
        G[down][2] = up;
        return ;
    }else DFS(up, down>>1, k-1);

    int val = 1<<(k-1);
    int m = down>>1;

    for(int ii=up, i=m+1; i<=down; i++, ii++){
        for(int j=up; j<=m; j++){
            G[i][j] = G[ii][j] + val;
        }
    }
    for(int ii=m+1, i=up; i<=m; i++, ii++){
        for(int jj=up, j=m+1; j<=down; j++, jj++){
            G[i][j] = G[ii][jj];
        }
    }
    for(int ii=up, i=m+1; i<=down; ii++, i++){
        for(int jj=up, j=m+1; j<=down; jj++, j++){
            G[i][j] = G[ii][jj];
        }
    }
}
int main(void)
{
    while(~scanf("%d", &k)){
        DFS(1, 1<<k, k);
        print();
    }
    return 0;
}
View Code

 

瞎 : 这种复制来复制去的操作,画个图,然后标个下标看着图打起来就很快而且出错率少

posted @ 2017-09-06 23:14  qwerity  阅读(337)  评论(0编辑  收藏  举报