sgu109

SGU109 Magic of David Copperfield II
题目大意:
著名的魔术师大卫-科波菲尔喜欢表演这样一个小魔术: 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

乍一看好难好难好神奇的样子,这可是大卫(神déng)-科波菲尔的魔术诶(也就是说做出这道题你就可以变魔术啦,神奇神奇的!:-O)
根据题目意思,魔术师是不知道观众怎么走的,那么他怎么会有把握删掉格子呢?
这里我们介绍染色法。

我们会发现,对于任意一点移动奇数次和移动偶数次可以到达的集合是不会相交的,所以我们可以把格子染成黑白两色,如:

13

4 5 6

79


那么,走奇数次一定是从黑格走到白格(或从白格走到黑格)
            走偶数次一定是从黑格走到黑格(或从白格走到白格)
利用这个特点,我们就可以快速判断观众下一步不能到达的格子了。

如果傻逼的把所有走不到的格子删了,那么大神的名声就被你毁了...

我们采取层层递进的方法(先以N为奇数为例):

  1    2   3    4   5

  6    7   8    9 10

11 12 13  14 15

16 17 18  19 20

21 22 23  24 25

变成:

   7   8   9

12 13 14

17 18 19

步骤如下:

1.让观众走到黑格,将最外围的白格全部删除。
2.让观众走到白格,将最外围的黑格全部删除。
3.反复步骤1、2,直至走到逼到一个格子上。

那么N为偶数呢?如下图:

  1    2    3   4

  5    6    7   8

  9  10 112

13  14 15 16


步骤如下:
1.让观众走到白格,将上面和右边的黑格子全部删除。
2.让观众走到黑格,将上面和右边的白格子全部删除。

这样我们就成功把偶数转化成奇数了。

这下会变这个魔术了吧!不过注意了:
1.这个方案肯定是不止一种的,如果你有自己的想法当然是好事。
2.走的步数没有什么特殊要求,记着每次不要重复,分奇偶就好(每次步数是>N的,仔细看题!)
3.注意一下你所逼近之后剩下正方形的格子编号(打错了会在TEST3之前WA掉)


下面附上我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
int group[101][101];
int n,t;
void work(int x,int y,int n) //处理矩阵(x,y)到(x+n-1,x+y-1)
{
  int i;
  if (n==1)
    return ;
  printf("%d",t);
  t+=2;
  for (i=1;i<=n;i+=2)
    printf(" %d",group[x][y+i-1]);
  for (i=3;i<n;i+=2)
    printf(" %d %d",group[x+i-1][y],group[x+i-1][y+n-1]);
  for (i=1;i<=n;i+=2)
    printf(" %d",group[x+n-1][y+i-1]);
  printf("\n");
  printf("%d",t);
  t+=2;
  for (i=2;i<=n;i+=2)
    printf(" %d",group[x][y+i-1]);
  for (i=2;i<n;i+=2)
    printf(" %d %d",group[x+i-1][y],group[x+i-1][y+n-1]);
  for (i=2;i<=n;i+=2)
    printf(" %d",group[x+n-1][y+i-1]);
  printf("\n");
  work(x+1,y+1,n-2);//递归思想
  return ;
}
void init()
{
  int i,j;
  scanf("%d",&n);
  t=n+(n%2==0);
  for (i=1;i<=n;i++) //给每个格子编号
    for (j=1;j<=n;j++)
      group[i][j]=(i-1)*n+j;
  if (n%2==0) //处理偶数情况
    {
	printf("%d",n);
	for (i=2;i<=n;i+=2)
	  printf(" %d",group[1][i]);
	for (i=3;i<=n;i+=2)
	  printf(" %d",group[i][n]);
	printf("\n");
	printf("%d",t);
	t+=2; //更新下次步数
	for (i=1;i<=n;i+=2)
	  printf(" %d",group[1][i]);
	for (i=2;i<=n;i+=2)
	  printf(" %d",group[i][n]);
	printf("\n");
	work(2,1,n-1);
	}
  else
    work(1,1,n);
  return ;
}
int main()
{
  init();
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值