题目描述
有 2n 个棋子(n≥4)排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为 n=5 的情况:
○○○○○●●●●●
移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如 n=5 时,成为:
○●○●○●○●○●
任务:编程打印出移动过程。
输入
一个整数
输出
移动过程
样例输入
7
样例输出
step 0:ooooooo*******--
step 1:oooooo--******o*
step 2:oooooo******--o*
step 3:ooooo--*****o*o*
step 4:ooooo*****--o*o*
step 5:oooo--****o*o*o*
step 6:oooo****--o*o*o*
step 7:ooo--***o*o*o*o*
step 8:ooo*o**--*o*o*o*
step 9:o--*o**oo*o*o*o*
step 10:o*o*o*--o*o*o*o*
step 11:--o*o*o*o*o*o*o*
分析
这道题看似不怎么好做,但只要细心一点观察样例,就会发现这题是一道极水的题:每经过两步,'o' 和 '*' 的排列方式就和原来一样了,只不过数目上各减少了一个,还有不同的是后面又多了一个 'o*'。
但是样例中到了step 7(n == 4)的时候就没有规律了,因此后面的完全可以固输,在补全 'o*'。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 const int maxn = 1e5 + 5; 8 int n; 9 char a[maxn]; 10 void final(int step) //固输 11 { 12 printf("step %d:%s%s ", step, "ooo*o**--", a + 10); 13 printf("step %d:%s%s ", ++step, "o--*o**oo", a + 10); 14 printf("step %d:%s%s ", ++step, "o*o*o*--o", a + 10); 15 printf("step %d:%s%s ", ++step, "--o*o*o*o", a + 10); 16 return; 17 } 18 void move(int n) 19 { 20 int step = 0; 21 for(int i = n; i >= 4; --i) //当 n >= 4 时循环模拟 22 { 23 a[i + 1] = a[i + 2] = '*'; 24 a[2 * i + 1] = a[2 * i + 2] = '-'; 25 printf("step %d:%s ", step, a + 1); step++; 26 a[2 * i + 1] = 'o'; a[2 * i + 2] = '*'; 27 a[i] = a[i + 1] = '-'; 28 printf("step %d:%s ", step, a + 1); step++; 29 } 30 final(step); 31 } 32 33 int main() 34 { 35 freopen("chessman.in", "r", stdin); 36 freopen("chessman.out", "w", stdout); 37 scanf("%d", &n); 38 for(int i = 1; i <= n; ++i) a[i] = 'o'; 39 for(int i = n + 1; i <= 2 * n; ++i) a[i] = '*'; 40 a[2 * n + 1] = a[2 * n + 2] = '-'; 41 move(n); 42 return 0; 43 }