SGU 109.Magic of David Copperfield II

时间: 0.50 sec

空间: 4096 KB

题目

       著名的魔术师大卫-科波菲尔喜欢表演这样一个小魔术: N*N个不同图案构成N行N列的表格在电视上出现,我们为了方便研究,把这些格子编号:

1                     2                   ...               N

...                    ...
...                    ...

N*(N-1)+1    N*(N-1)+2   ...             N*N

 

所有观众首先将手指指向左上角的小格(1号图案)然后魔术开始:魔术师命令观众在图案中移动手指 K1次(一次移动是指移动到当前图案上下左右的另一个图案),之后魔术师轻挥手指,有一些图案所在的格子不见了(被删掉的格子以后不能经过),魔术师解释说"你不可能在这里!", ....他说对了 - 你的手指并不在他删掉的任一格子上。接着他再让观众移动手指K2次, 等等. 最后他删得只剩下1个格子,面带微笑地宣布胜利 "我抓到你了!" (鼓掌....).

就在刚才,魔术师又想完一次这个小把戏。不幸的是,他昨天很累,你了解当人在头痛的时候变戏法是很困难的。你需要编写一个程序来帮助科波菲尔完成这个小魔术。

输入

       包括一个整数 N (1<N<101).

输出

你的程序需要按照以下格式输出:
K1 X1,1 X1,2 ... X1,m1
K2 X2,1 X2,2 ... X2,m2
...
Ke Xe,1 Xe,2 ... Xe,me
Ki表示第i次时观众需要移动手指的次数(N<=Ki<300)。所有的Ki中没有重复 (如果i<>j那么Ki<>Kj)。 Xi,1 Xi,2 ... Xi,mi 是当观众完成 Ki 次移动后科波菲尔需要删掉的图案编号(每次删除的图案个数任意,但是每个图案不能不能被删除两次,每一轮必须删掉至少1个图案)。每一个新轮回必须占一个新行。整数间都用空格隔开,且最后只能留下一个图案。

样例输入

3

样例输出

3 1 3 7 9

5 2 4 6 8




{=====================}

分析

     先提取一些要点:

  • 只能上下左右移动,说明其奇偶性(就像国际象棋的棋盘,黑白块)
  • 300>ki>=n (开始我没注意到这点,OJ反馈的信息是 PE。。。结果误会又PE几次)
  • 每次都必须删掉一些格子
  • 最后只剩一个格子

     从上面看来,还是比较简单的,


     假设认为棋盘G[i][j],当i+j的和为奇数时,称为奇块,和为偶数时称为偶块;


     所有的从G[1][1],开始那么移动奇数次,必定是从一个偶块,移动到了一些奇块上。


     那么只有以特定的方法在移动在一中格子上后,删除一些奇偶性不同的格子。


这里提供两种方法


 

 

     第一种从右下角往左上角删


           5
      5   4
      5    4   3
    5    4    3   2
   5    4    3    2   1

      数字代表删的顺序,k从不小于n奇数开始,不断加2,不会超过300,这样删最后留下的是G[1][1];



=======================

 

        第二种从四周删


  1   2   1   2    1
  2          2
  1          1
  2          2
  1    2   1    2    1

 

         输出的将结果和样例一样

 

         最后留下的是中间的格子,可以用递归的方法,不断缩小n

      

       例如上面n=5,在两次删除过后,中间留下了3*3的矩阵

 

       要注意的是当n==2 时需要同方法那样特殊处理

 

           如下

       1       2
       2  

 

 

参考代码

方法一:

#include <iostream>
using namespace std; 
int main(){
    int N;
    cin>>N;
    int K=N;
    if(k>2)cout<<K;
    for (int x=1;x<=N;x++)
        for (int y=1;y<=N;y++)
            if (x+y>=N+3)
               cout<<" "<<(x-1)*N+y;
    if(k>2)cout<<endl;
    for (int XpY=N+2;XpY>2;XpY--){
        while ((++K)%2==0);
        cout<<K;
        for (int x=1;x<=N;x++)
            for (int y=1;y<=N;y++)
                if (x+y==XpY)
                   cout<<" "<<(x-1)*N+y;
        cout<<endl;
    }
    return 0;
}

 

 ================================

 

方法二:

 

#include <cstdio>
int n, p,k;
void make (int t, int x, int k) {
    if (x==2) {
              int i=(t-1)*n+t;
        printf ("%d %d\n", k, i);
        printf ("%d %d %d\n", k+2, i+ 1, i + n);
    }
    else {
        printf ("%d", k);
        for (int i = t; i < t + x; i++)
            for (int j = t; j < t + x; j++) {
                if ( ((i + j) & 1) == 0 && (i == t || i == t + x - 1 || j == t || j == t + x - 1) )
                    printf (" %d", (i - 1) * n + j);
            }
        printf ("\n%d", k + 2);
        for (int i = t; i < t + x; i++)
            for (int j = t; j < t + x; j++) {
                if ( ((i + j) & 1) == 1 && (i == t || i == t + x - 1 || j == t || j == t + x - 1) )
                    printf (" %d", (i - 1) * n + j);
            }
              putchar (10);
        if (x - 2 > 1)   make (t+1, x - 2,k+4);
    }
}
int main() {
    scanf("%d",&n);
    if (n & 1) k=n;
    else
              k=n+1;
    make (1, n, k);
    return 0;
}

 

 

http://www.cnblogs.com/keam37/ keam所有 转载请注明出处

posted @ 2014-06-30 00:32  keambar  阅读(235)  评论(0编辑  收藏  举报