题目: 下过中国象棋的朋友都知道,双方的“将”和“帅”相隔遥远,并且他们不能照面,在象棋残局中,许多高手能利用这一规则走出精妙的杀招,假设棋盘上只有“将”和“帅”二子(如图)(为了下面叙述方便,我们约定用A表示“将”,B表示“帅”):
A、B二子被限制在己方的3x3的格子里运动,例如,在如上表格里,A被正方形{d10,f10,d8,f8}包围,而B被正方形{d3,f3,d1,f1}包围。每一步,A、B分别可以横向或者纵向移动一格,但是不能沿对角线移动,另外,A不能面对B,也就是说,A和B不能处在一纵向直线上(比如A在d(10)的位置上,那么B就不能在d1、d2以及d3)。
请写出一个程序,输出A、B所有合法的位置,要求在代码中只能使用一个变量。
我的理解:下过象棋的都知道,将帅只能在“宫”中,而且不能碰面。这个题目就是要算出将帅有多少种合法的摆法。
当然,这肯定得用到循环。所以第一步,将棋盘坐标有序化,将其可能的位置用数字代表:
这样就可以用两层循环+判断解决问题了,但是有个限制,只能程序中使用一个变量!Java中的for循环果断不能用啊!但是单用while也不好实现。 这里我考虑将第一层循环与第二层循环合并,这样就绕过这个问题咯。用一个两位数的十位与个位分别表示A与B,那么合并的循环就可以取99:上代码:
public static void section1(){
int i = 99;
while(i>10){
if(i%10!=0){
if((i/10 - 1)/3 != (i%10 - 1)/3){
System.out.println( "a:" + (i/10) + ",b:" + (i%10));
}
}
i--;
}
}
考虑好看,可以添加两个常量,表示位置,如下:
public static void section2(){
final String[] a = {"d10","d9","d8","e10","e9","e8","f10","f9","f8"};
final String[] b = {"d3","d2","d1","e3","e2","e1","f3","f2","f1"};
int i = 99;
while(i>10){
if(i%10!=0){
if((i/10 - 1)/3 != (i%10 - 1)/3){
System.out.println( "a:" + a[(i/10) -1] + ",b:" + b[(i%10) -1]);
}
}
i--;
}
}
当然也可以利用强制类型转换,直接在输出的字母,如下:
public static void section3(){
int i = 99;
while(i>10){
if(i%10!=0){
if((i/10 - 1)/3 != (i%10 - 1)/3){
System.out.println( "将:" + (char)((i/10 -1)/3 + 100) + ((i/10 -1)%3 + 8) + ",帅:" + (char)((i%10 -1)/3 + 100) + ((i%10 -1)%3 + 1));
}
}
i--;
}
}
最终结果:
将:f10,帅:e3
将:f10,帅:e2
将:f10,帅:e1
将:f10,帅:d3
将:f10,帅:d2
将:f10,帅:d1
将:f9,帅:e3
将:f9,帅:e2
将:f9,帅:e1
将:f9,帅:d3
将:f9,帅:d2
将:f9,帅:d1
将:f8,帅:e3
将:f8,帅:e2
将:f8,帅:e1
将:f8,帅:d3
将:f8,帅:d2
将:f8,帅:d1
将:e10,帅:f3
将:e10,帅:f2
将:e10,帅:f1
将:e10,帅:d3
将:e10,帅:d2
将:e10,帅:d1
将:e9,帅:f3
将:e9,帅:f2
将:e9,帅:f1
将:e9,帅:d3
将:e9,帅:d2
将:e9,帅:d1
将:e8,帅:f3
将:e8,帅:f2
将:e8,帅:f1
将:e8,帅:d3
将:e8,帅:d2
将:e8,帅:d1
将:d10,帅:f3
将:d10,帅:f2
将:d10,帅:f1
将:d10,帅:e3
将:d10,帅:e2
将:d10,帅:e1
将:d9,帅:f3
将:d9,帅:f2
将:d9,帅:f1
将:d9,帅:e3
将:d9,帅:e2
将:d9,帅:e1
将:d8,帅:f3
将:d8,帅:f2
将:d8,帅:f1
将:d8,帅:e3
将:d8,帅:e2
将:d8,帅:e1
改进的地方:可以利用九进制减少循环的次数,改循环数为81,用除九的商表示A,除九的模表示B,《编程之美》书中,也有这种答案。用十进制是最先想到,也是最直观的方法。