【题目描述】
有2n个棋子(n≥4)排成一行,开始位置为白子全部在左边,黑子全部在右边,如下图为n=5的情形:
○○○○○●●●●●
移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。如n=5时,成为:
○●○●○●○●○●
任务:编程打印出移动过程。
【输入】
输入n。
【输出】
移动过程。
【输入样例】
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* step10:o*o*o*--o*o*o*o* step11:--o*o*o*o*o*o*o*
【思路】:分治(NM分治的题肯定是分治了,怎么分啊?)其实这个题你仔细瞅瞅,就好发现它的棋子移动是有规律的,在结合分治的思想,把大问题分解成类似的小问题:
所以,问题分为两步:
1.把中间位置的一对黑白棋移到最右边。
2.把最左边的一对黑棋移到中间的空位上。
然后在看样例:
ooooooo*******-- oooooo--******o* oooooo******--o* ooooo--*****o*o* ooooo*****--o*o* oooo--****o*o*o* oooo****--o*o*o* ooo--***o*o*o*o* ooo*o**--*o*o*o* o--*o**oo*o*o*o* o*o*o*--o*o*o*o* --o*o*o*o*o*o*o*
发现就是这样的,嘿嘿嘿(好像思路顺序不对啊,逃)
当n>4时,总是将中间的一对两个不同的棋子移到最右边的空位,然后再把最左边的黑棋子移到中间,如此往复,直到剩下四对黑白棋没有移动。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> using namespace std; const int maxn=999999999; const int minn=-999999999; int n; int step,cgp; char a[520]; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } void print() { printf("step%2d:",step); for(int i=0; i<2*n+2; i++) printf("%c",a[i]); printf(" "); step++; } void fz(int k) { int j; for(j=0; j<2; j++) { a[cgp+j]=a[k+j-1]; a[k+j-1]='-'; } cgp=k-1; print(); } void move(int m) { int i,k; if(m==4) { fz(4); fz(8); fz(2); fz(7); fz(1); } else { fz(m); fz(m*2-1); move(m-1); } } int main() { n=read(); for(int i=0; i<n; ++i) { a[i]='o'; } for(int i=n; i<2*n; ++i) { a[i]='*'; } for(int i=2*n; i<=2*n+1; ++i) { a[i]='-'; } cgp=2*n; print(); move(n); return 0; }