题目:
请将8个给定的正整数(如1,2,3,4,5,6,7,8)分别放在一个正方体的8个角的顶点上,以实现如下要求(如果可能):正方体六个面上的四个角点整数之和相等?输出结果如:A1=1,A2=2...
求解如下
算法思路
根据题境,我们先做如下设定和术语说明,以便于后面的讨论:
1、正整数以1,2,3,4,。。。8表示,以便进行分析;
2、正方体顶点标示如上所示;
3、每一个面的四个顶点数总和,我们称为该面的面积;
4、每一条边的两个顶点数和,我们称为该边的长度;
通过分析,可以得到如下断言为真(采用上面设定及术语):
1、每个面的面积相等,且每个面的面积为36/2,即18;
2、正方体的对边相等;
3、整数1和(2,3)不在同一边,整数7和8不在同一边;
根据所得断言,可以得到如下求导公式和约束:
A1=1;
A4=18-A1-A2-A3=17-A2-A3;
A6=18-A1-A2-A5=17-A2-A5;
A7=18-A1-A3-A5=17-A3-A5;
A8=A1+A2-A7=2*A1+A2+A3+A5-18=A2+A3+A5-16;
A2,A3,A5为可变量,但是A2,A3不等于2,3
程序实现
通过以上算法分析,可用程序实现如下(Java实现):
package
qinysong.arithmetic;
public class CubeProblem {
public static void main(String[] args) {
System.out.println( " CubeProblem begin ........ " );
searchPeekNumber();
System.out.println( " CubeProblem end ........ " );
}
public static void printPeekNumbers( int [] peeks){
System.out.println( " the peek number:A1= " + peeks[ 0 ] + " ;A2= " + peeks[ 1 ]
+ " ;A3= " + peeks[ 2 ] + " ;A4= " + peeks[ 3 ]
+ " ;A5= " + peeks[ 4 ] + " ;A6= " + peeks[ 5 ]
+ " ;A7= " + peeks[ 6 ] + " ;A8= " + peeks[ 7 ]);
}
// 核心函数,探寻各个顶点的数值
public static void searchPeekNumber(){
int [] peeks = new int [ 8 ];
int peekNumber = 0 ;
for ( int i = 4 ; i <= 8 ; i ++ ){
peeks[ 0 ] = 1 ;
peeks[ 1 ] = i;
for ( int j = 4 ; j <= 8 ; j ++ ){
if (hasUsed( 2 ,j, peeks)) continue ;
peeks[ 2 ] = j;
peekNumber = getPeekNumber( 3 , peeks);
peeks[ 3 ] = peekNumber;
for ( int k = 2 ; k <= 8 ; k ++ ){
if (hasUsed( 4 ,k, peeks)) continue ;
peeks[ 4 ] = k;
peekNumber = getPeekNumber( 5 , peeks);
if (hasUsed( 5 ,peekNumber, peeks)) continue ;
peeks[ 5 ] = peekNumber;
peekNumber = getPeekNumber( 6 , peeks);
if (hasUsed( 6 ,peekNumber, peeks)) continue ;
peeks[ 6 ] = peekNumber;
peekNumber = getPeekNumber( 7 , peeks);
if (hasUsed( 7 ,peekNumber, peeks)) continue ;
peeks[ 7 ] = peekNumber;
printPeekNumbers(peeks);
}
}
}
}
/**
* 判断获取的顶点值是否在之前的顶点使用过
* @param index int 将要赋值的顶点索引
* @param peekNumber int 获取的顶点值
* @return boolean 是否在之前的顶点使用过
*/
public static boolean hasUsed( int index, int peekNumber, int [] peeks){
if (peekNumber <= 0 ) return true ;
for ( int i = 0 ; i < index; i ++ ){
if (peeks[i] == peekNumber){
return true ;
}
}
return false ;
}
/**
* 取得某一顶点的数值
* 根据推导公式:
* A4=18-A1-A2-A3;A6=18-A1-A2-A5;A7=18-A1-A3-A5;A8=2*A1+A2+A3+A5-18;
* 这里取 A1=1
* @param peek int 顶点标号
* @return int 顶点数值
*/
public static int getPeekNumber( int peek, int [] peeks) {
switch (peek) {
case 0 :
return 1 ;
case 3 :
return 17 - peeks[ 1 ] - peeks[ 2 ];
case 5 :
return 17 - peeks[ 1 ] - peeks[ 4 ];
case 6 :
return 17 - peeks[ 2 ] - peeks[ 4 ];
case 7 :
return peeks[ 1 ] + peeks[ 2 ] + peeks[ 4 ] - 16 ;
default :
return 0 ;
}
}
}
public class CubeProblem {
public static void main(String[] args) {
System.out.println( " CubeProblem begin ........ " );
searchPeekNumber();
System.out.println( " CubeProblem end ........ " );
}
public static void printPeekNumbers( int [] peeks){
System.out.println( " the peek number:A1= " + peeks[ 0 ] + " ;A2= " + peeks[ 1 ]
+ " ;A3= " + peeks[ 2 ] + " ;A4= " + peeks[ 3 ]
+ " ;A5= " + peeks[ 4 ] + " ;A6= " + peeks[ 5 ]
+ " ;A7= " + peeks[ 6 ] + " ;A8= " + peeks[ 7 ]);
}
// 核心函数,探寻各个顶点的数值
public static void searchPeekNumber(){
int [] peeks = new int [ 8 ];
int peekNumber = 0 ;
for ( int i = 4 ; i <= 8 ; i ++ ){
peeks[ 0 ] = 1 ;
peeks[ 1 ] = i;
for ( int j = 4 ; j <= 8 ; j ++ ){
if (hasUsed( 2 ,j, peeks)) continue ;
peeks[ 2 ] = j;
peekNumber = getPeekNumber( 3 , peeks);
peeks[ 3 ] = peekNumber;
for ( int k = 2 ; k <= 8 ; k ++ ){
if (hasUsed( 4 ,k, peeks)) continue ;
peeks[ 4 ] = k;
peekNumber = getPeekNumber( 5 , peeks);
if (hasUsed( 5 ,peekNumber, peeks)) continue ;
peeks[ 5 ] = peekNumber;
peekNumber = getPeekNumber( 6 , peeks);
if (hasUsed( 6 ,peekNumber, peeks)) continue ;
peeks[ 6 ] = peekNumber;
peekNumber = getPeekNumber( 7 , peeks);
if (hasUsed( 7 ,peekNumber, peeks)) continue ;
peeks[ 7 ] = peekNumber;
printPeekNumbers(peeks);
}
}
}
}
/**
* 判断获取的顶点值是否在之前的顶点使用过
* @param index int 将要赋值的顶点索引
* @param peekNumber int 获取的顶点值
* @return boolean 是否在之前的顶点使用过
*/
public static boolean hasUsed( int index, int peekNumber, int [] peeks){
if (peekNumber <= 0 ) return true ;
for ( int i = 0 ; i < index; i ++ ){
if (peeks[i] == peekNumber){
return true ;
}
}
return false ;
}
/**
* 取得某一顶点的数值
* 根据推导公式:
* A4=18-A1-A2-A3;A6=18-A1-A2-A5;A7=18-A1-A3-A5;A8=2*A1+A2+A3+A5-18;
* 这里取 A1=1
* @param peek int 顶点标号
* @return int 顶点数值
*/
public static int getPeekNumber( int peek, int [] peeks) {
switch (peek) {
case 0 :
return 1 ;
case 3 :
return 17 - peeks[ 1 ] - peeks[ 2 ];
case 5 :
return 17 - peeks[ 1 ] - peeks[ 4 ];
case 6 :
return 17 - peeks[ 2 ] - peeks[ 4 ];
case 7 :
return peeks[ 1 ] + peeks[ 2 ] + peeks[ 4 ] - 16 ;
default :
return 0 ;
}
}
}
执行结果如下





















算法特性
因为该算法是根据分析问题的数学模型,找到推导公式及数值约束,然后直接推导答案,而不是采用通过遍历每一种可能性进行判断,所以效率非常好