编程之美上的一道题:要求将帅不能照面,找到有多少种方式摆放“将”和“帅”,而且只能使用一个变量。
思考:如果蛮力法解决,只需要罗列出所有的可能性,然后排除掉那些不满足条件的情况就是结果了。但是,这里只能用一个变量保存结果,所以,需要一点技巧,先说一下《编程之美》是的解法2,因为解法2是最精妙的,个人认为,提供了一种新型的思考方式。先给出将帅在棋局的分布,有一个感观的认识再继续下面的操作:
解法二:我们可以这么做,下面的二维特殊数k{1,2,3,4,5,….9},其中k=1,2,3,4,…..9.表示A中的k和B中的1,2,…9搭配成一对,这样子的话就可以搭配出9*9=81种可能性.理论上,我们只需要遍历完这81种情况就可以找到结果。A格子和B格子的棋子只有在同一列才会产生冲突。那么重点就是如何找到列数。
先列举出所以的可能性组合:
1{1,1}{1,2}{1,3}{1,4}{1,5}{1,6}{1,7}{1,8}{1,9}
2{2,1}{2,2}{2,3}{2,4}{2,5}{2,6}{2,7}{2,8}{2,9}
3{3,1}{3,2}{3,3}{3,4}{3,5}{3,6}{3,7}{3,8}{3,9}
4{4,1}{4,2}{4,3}{4,4}{4,5}{4,6}{4,7}{4,8}{4,9}
5{5,1}{5,2}{5,3}{5,4}{5,5}{5,6}{5,7}{5,8}{5,9}
6{6,1}{6,2}{6,3}{6,4}{6,5}{6,6}{6,7}{6,8}{6,9}
7{7,1}{7,2}{7,3}{7,4}{7,5}{7,6}{7,7}{7,8}{7,9}
8{8,1}{8,2}{8,3}{8,4}{8,5}{8,6}{8,7}{8,8}{8,9}
9{9,1}{9,2}{9,3}{9,4}{9,5}{9,6}{9,7}{9,8}{9,9}
第1行就是A中第1格和B中的九格对应的情况,其它类比如是
像for(i=1;i<=81;++i)中的i,
如果我们想确定它是A中的第几格,怎么办?可以对i除以9,就知道它是第几行,即A中第几格,如果还想知道它在A中第几列,继续对它模3即可。
现在开始考虑B中的情况,如何知道当前i是B中的第几格?这个问题可以转化成如何知道它是上面二维数组中第几列,只需要对i模上9即可,那么如何知道它是B中的第几列呢?继续对它模上3即可。
小结拓展:
我们知道A[i][j]实质上表示的是A数组中(i*cols+j)号元素,那么,如果我们知道元素是第k号元素了,要如何确定它的行号和列号呢?row=k/cols,col=k%cols.再把这个基本思路套到上面应该能够找到一点灵感了。
#include<stdio.h>
int main()
{
int i=81;
while(i--)
{
if( i/9%3 == i%9%3)//i/9求的是行号(A中号码),i%9求的是列号(B中号码)
continue;
printf("%d %d\n",i/9+1,i%9+1);//输出A,B中的号码
}
}
总结:
可以将A中的9个格子{1,2,3,4,5,6,7,8,9}当成行号,将B中的9个格子{1,2,3,4,5,6,7,8,9}当成列号,那么就可以组成一个A[i][j]二维数组,只不过题目要求我们只能使用一个变量,否则我们只需要保存两个变量i,j,遍历完整个数组就可以了。但是,我们也可以用一维数组的方式存储二维数组的下标,假定一维数组的下标是k,则i=k/cols,j=k%cols.
这让我想到这篇博文的35和36行。http://blog.csdn.net/linraise/article/details/12571025
剩下的就可以完全按照二维数组的形式解决这个问题了。
解法三:用一个结构体保存两个变量,实质上和直接使用二维下标的思路一样。这里不再多说。
int main()
{
struct
{
unsigned char a:4;
unsigned char b:4;
} i;
for(i.a=1;i.a<=9;++i.a)
{
for(i.b=1;i.b<=9;++i.b)
{
if( i.a % 3 != i.b % 3)
printf("A = %d, B = %d\n",i.a,i.b);
}
}
}