編程之美- 中國象棋將帥問題

問題描述:
在中國象棋規則中,將和帥規定只能在田字格中移動,且將和帥是不能碰面的,請求解出全部可能的符合規則的將帥位置。
限制條件:
只能使用一個字節的變量java

問題解答:
剛看到問題時,以爲問題自己的邏輯關係很簡單,限制條件纔是本題的精妙之處,如何只用一個字節來表示全部須要用到變量,咱們一步一步的分析;
首先,將題目中所提的場景使用數學方法描述爲:
                                                               7    8    9
                    將的移動範圍爲 Matrix A  =4    5    6 
                                                               1    2    3
同理:
                                                               7    8    9
                    帥的移動範圍爲 Matrix B  =4    5    6 
                                                               1    2    3
若是沒有限制條件,則本題解法很容易想到:
S1:a=將當前位置號;
S2:b=帥當前位置號;
S3: IF abs(a-b)%3 != 0 THEN 符合  ELSE 不符合;不能處於同一列,則好比A.7-B.1=6,6%3=0
可是,有了限制條件後,須要將a,b變爲一個單字節的變量,這最早想到的就是利用除法,由於四則運算中只有除法能夠將一個數變爲兩個, N/n = q...r N被除數,n除數,q商,r餘數,這樣咱們就找到了使a,b變爲一個數的方法。
根據A,B兩個矩陣易知:一、總共存在81種可能的狀況;二、從新將矩陣轉爲以0爲開始,易於計算
設Num爲某種狀況的標號,則Num的範圍爲[0,80]共81種,a=Num/9,b=Num%9
則能夠獲得a,b,並利用S3就能夠獲得全部符合規則的解;
從新整理算法爲:
for Num=0:80
     a=Num/9;
     b=Num%9;
     if(abs(a-b))!=0
        printf("a = %d, b = %d"a+1,b+1);算法

或者數組

int var = 81;
  while( var-- )
  {
    if( var / 9 % 3 == var % 9 % 3 )//發生衝突
     continue;
    else
 printf(/** 打印可行的位置 **/);
  }oop

整數i能夠由部兩分組成,即var=(var/9)*9+var%9 ,其中var<n。咱們注意到,在i從81到0變化的過程當中,var%9的變化至關於最內層循環b,var/9的變話相對於最外層循環a。spa

 

package cglib;.net

public class jiekou {遞歸

    
      
    /**
     * @param args
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
        // 7 8 9
        // 4 5 6
        // 1 2 3
        
        // 7 8 9
        // 4 5 6
        // 1 2 3
       int i = 81;
       System.out.println(i);
        while((i--)!=0)
        {   
            System.out.println("while:"+i);
            if((i / 9) % 3 == (i % 9) % 3)
                continue;
           System.out.println("A = "+((i /9 )+1)+","+"B = "+((i%9)+1));
            
            
        }
        
     
          
    }
    }get

 

輸出:數學

81
while:80
while:79
A = 9,B = 8
while:78
A = 9,B = 7
while:77
while:76
A = 9,B = 5
while:75
A = 9,B = 4
while:74
while:73
A = 9,B = 2
while:72
A = 9,B = 1
while:71
A = 8,B = 9
while:70
while:69
A = 8,B = 7
while:68
A = 8,B = 6
while:67
while:66
A = 8,B = 4
while:65
A = 8,B = 3
while:64
while:63
A = 8,B = 1
while:62
A = 7,B = 9
while:61
A = 7,B = 8
while:60
while:59
A = 7,B = 6
while:58
A = 7,B = 5
while:57
while:56
A = 7,B = 3
while:55
A = 7,B = 2
while:54
while:53
while:52
A = 6,B = 8
while:51
A = 6,B = 7
while:50
while:49
A = 6,B = 5
while:48
A = 6,B = 4
while:47
while:46
A = 6,B = 2
while:45
A = 6,B = 1
while:44
A = 5,B = 9
while:43
while:42
A = 5,B = 7
while:41
A = 5,B = 6
while:40
while:39
A = 5,B = 4
while:38
A = 5,B = 3
while:37
while:36
A = 5,B = 1
while:35
A = 4,B = 9
while:34
A = 4,B = 8
while:33
while:32
A = 4,B = 6
while:31
A = 4,B = 5
while:30
while:29
A = 4,B = 3
while:28
A = 4,B = 2
while:27
while:26
while:25
A = 3,B = 8
while:24
A = 3,B = 7
while:23
while:22
A = 3,B = 5
while:21
A = 3,B = 4
while:20
while:19
A = 3,B = 2
while:18
A = 3,B = 1
while:17
A = 2,B = 9
while:16
while:15
A = 2,B = 7
while:14
A = 2,B = 6
while:13
while:12
A = 2,B = 4
while:11
A = 2,B = 3
while:10
while:9
A = 2,B = 1
while:8
A = 1,B = 9
while:7
A = 1,B = 8
while:6
while:5
A = 1,B = 6
while:4
A = 1,B = 5
while:3
while:2
A = 1,B = 3
while:1
A = 1,B = 2
while:0class

 

  其實這個問題還能夠進行一些擴展,即如何利用一個變量達到三重循環的效果。也就是說,若是給定下面的循環:

  int counter = 0;
  for( int i = 0; i < 5; i++ )
 for( int j = 0; j < 4; j++ )
   for( int k = 0; k < 3; k++ )
   {
    System.out.println("counter="+counter+"/t, i="+i+", j="+j+", k="+k);
    counter++;
   }
   其結果以下:
 counter=0 , i=0, j=0, k=0
 counter=1 , i=0, j=0, k=1
 counter=2 , i=0, j=0, k=2
 counter=3 , i=0, j=1, k=0
 counter=4 , i=0, j=1, k=1 
    ....中間略
    counter=59  , i=4, j=3, k=2
  
  實際上就是對原始的中國象棋將帥問題進行了一個擴展,即在棋盤上添加一個「王」,其行走規則和將帥 同樣。因而棋盤變成了三國爭霸:-) ,將帥王能夠走動的格子數分別爲三、四、5,它們之間的互斥條件能夠按須要設定。
  
   這時,就須要只用一個變量遍歷一個三重循環。
  
   只用一個變量解決擴展的中國象棋將帥問題,咱們的代碼應該是以下的樣子:
   int var = 3*4*5;
   while( var-- )
   {
     if( /** 衝突條件 **/ )//發生衝突
      continue;
     else   
         printf(/** 打印可行的位置 **/);
   }

   在衝突條件中,咱們須要知道var取得某個特定的值(即第var+1次循環)的時候的i,j,k分別是多少(這樣咱們才能斷定將帥位置是否衝突)
  
   從上例的結果中咱們能夠看到,counter的值(即當前的循環次數)和三元組(i,j,k)是一一對應的,越是外層的循環變化越慢,他們知足什麼關係呢?
  
   k的取值最好肯定,咱們都知道是var%3。
   在原始的將帥問題中咱們知道,j的值應該是 var/3,可是因爲j上面還有一層循環,就須要作些調整,變成var/3%4
   最外層循環i的值則爲(var/(3*4))%5.
     
     即:k=var%3      //其下沒有循環了
             j=var/3   //其下有幾個循環長度爲3的循環
            i=var/(3*4). //其下有幾個循環長度爲3*4的循環
 
  因而4重循環的公式咱們也能夠輕鬆得出:
  for( int i = 0; i < 5; i++ )
     for( int j = 0; j < 4; j++ )
       for( int k = 0; k < 3; k++ )
         for( int p = 0; p < 2; p++ )
    
   p=var%2 //其下沒有循環了
   k=var/2      //其下有幾個循環長度爲2的循環
   j=var/(2*3)) //其下有幾個循環長度爲2*3的循環
   i=var/(2*3*4)//其下有幾個循環長度2*3*4的循環
  
   下面就是一個變量實現三重循環

int var = 2*3*4*5;
while( var-- > 0){
 System.
out.println("var="+var+" , i="+((var/(2*3*4))%5)+
                                                    ", j ="+((var/(2*3))%4)+",
                                                       k="+((var/2)%3)+",
                                                       p
="+var%2);
}


   
   結果是:
   var=119 , i=4, j=3, k=2, p=1
   var=118 , i=4, j=3, k=2, p=0
   var=117 , i=4, j=3, k=1, p=1
   ...中間略
   var=5 , i=0, j=0, k=2, p=1
   var=4 , i=0, j=0, k=2, p=0
   var=3 , i=0, j=0, k=1, p=1
   var=2 , i=0, j=0, k=1, p=0
   var=1 , i=0, j=0, k=0, p=1
   var=0 , i=0, j=0, k=0, p=0  

因此概括總結

對於 b*a = i ,咱們能夠用以下公式展開


    loop1=i%b;
    loop2=(i/b)%a 

 

其中loop1是內層循環,loop2是外層循環

那麼若是 a 自己就是 j*k 組成的呢?

因爲 j*k = i/b  ,套用公式獲得

   

    loop1= (i/b)%j

    loop2= ((i/b)/j)%k 

 

由此能夠得出N重時的公式,假設 an * a(n-1) * ....... * a3 * a2 * a1 =  N

 

    loop1=N%a1---至關於最小因子

    loop2=(N/(a1))%a2

    loop3=(N/(a1a2))%a3

    .....

    loopN=(N/(a1.....an))%an

則對於給定的 an * a(n-1) * ....... * a3 * a2 * a1 =  N ,展開式是 ( Nzk 意思是N的展開 )

Nzk =  (N/(a1.....an))%an +  " ,  "+  .....  (N/(a1a2))%a3 + " , " +  (N/(a1))%a2 + " , " +  N%a1

得出

Nzk  =  ((N/(a1.....an))%an +  " ,  "+  .....  (N/(a1a2))%a3 + " , " +  (N/(a1))%a2 )+ " , " +  N%a1

得出

Nzk =   (an * a(n-1) * ....... * a3 * a2)zk    +  " , " +  N%a1

————   (an * a(n-1) * ....... * a3 * a2)zk 就至關於 (N/(a1.....an))%an +  " ,  "+  .....  (N/(a1a2))%a3 + " , " +  (N/(a1))%a2 ,也就是(N-1) zk

得出

Nzk =  (N/a1)zk  +  " , " +  N%a1

至此得出了遞歸公式,

N的展開式 = (N/(N的最後一個因數)) 的展開式 +  ( N 模(N的最後一個因數))

 

package cglib;

import java.util.ArrayList;

public class jiekou {

    static void singleLineLoop(ArrayList<Integer> args,int amount){  
          
        //若是數組只剩一個元素,則已經到了an , 用 amount % an 便可,  
        //由於 amount 就是 (N/(a1.....an))  
        if (args.size() == 1){  
            System.out.print("" + (amount%args.get(0)) + "/n");
            System.out.println();  
            return;  
        }         
                  
        //輸出當前數組的最後一個元素  
        System.out.print("" + ((amount%args.get(args.size()-1))) + " , " );  
        //繼續遞歸調用  
        singleLineLoop(new ArrayList(args.subList(0, args.size()-1)),amount/args.get(args.size()-1));  
    }  
      
    static void multiLoop(ArrayList<Integer> args,int amount){  
          
        while(amount-->0){  
            System.out.print("var (" + amount +") :" );  
              
            // N%a1部分  
            System.out.print("" + ((amount%args.get(args.size()-1))) + " , " );  
              
            //遞歸實現(N/a1)zk  
            singleLineLoop(new ArrayList(args.subList(0, args.size()-1)),amount/args.get(args.size()-1));  
        }  
          
    }  
      
    /**
     * @param args
     */  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
          
        ArrayList<Integer> li = new ArrayList<Integer>();     
       li.add(2);  
       li.add(3);  
       li.add(4);  
       li.add(5);  
        int amount = 2*3*4*5;
        
     
   
 
        multiLoop(li,amount);  
          
    }
    }   

輸出:

var (119) :4 , 3 , 2 , 1/n var (118) :3 , 3 , 2 , 1/n var (117) :2 , 3 , 2 , 1/n var (116) :1 , 3 , 2 , 1/n var (115) :0 , 3 , 2 , 1/n var (114) :4 , 2 , 2 , 1/n var (113) :3 , 2 , 2 , 1/n var (112) :2 , 2 , 2 , 1/n var (111) :1 , 2 , 2 , 1/n var (110) :0 , 2 , 2 , 1/n var (109) :4 , 1 , 2 , 1/n var (108) :3 , 1 , 2 , 1/n var (107) :2 , 1 , 2 , 1/n var (106) :1 , 1 , 2 , 1/n var (105) :0 , 1 , 2 , 1/n var (104) :4 , 0 , 2 , 1/n var (103) :3 , 0 , 2 , 1/n var (102) :2 , 0 , 2 , 1/n var (101) :1 , 0 , 2 , 1/n var (100) :0 , 0 , 2 , 1/n var (99) :4 , 3 , 1 , 1/n var (98) :3 , 3 , 1 , 1/n var (97) :2 , 3 , 1 , 1/n var (96) :1 , 3 , 1 , 1/n var (95) :0 , 3 , 1 , 1/n var (94) :4 , 2 , 1 , 1/n var (93) :3 , 2 , 1 , 1/n var (92) :2 , 2 , 1 , 1/n var (91) :1 , 2 , 1 , 1/n var (90) :0 , 2 , 1 , 1/n var (89) :4 , 1 , 1 , 1/n var (88) :3 , 1 , 1 , 1/n var (87) :2 , 1 , 1 , 1/n var (86) :1 , 1 , 1 , 1/n var (85) :0 , 1 , 1 , 1/n var (84) :4 , 0 , 1 , 1/n var (83) :3 , 0 , 1 , 1/n var (82) :2 , 0 , 1 , 1/n var (81) :1 , 0 , 1 , 1/n var (80) :0 , 0 , 1 , 1/n var (79) :4 , 3 , 0 , 1/n var (78) :3 , 3 , 0 , 1/n var (77) :2 , 3 , 0 , 1/n var (76) :1 , 3 , 0 , 1/n var (75) :0 , 3 , 0 , 1/n var (74) :4 , 2 , 0 , 1/n var (73) :3 , 2 , 0 , 1/n var (72) :2 , 2 , 0 , 1/n var (71) :1 , 2 , 0 , 1/n var (70) :0 , 2 , 0 , 1/n var (69) :4 , 1 , 0 , 1/n var (68) :3 , 1 , 0 , 1/n var (67) :2 , 1 , 0 , 1/n var (66) :1 , 1 , 0 , 1/n var (65) :0 , 1 , 0 , 1/n var (64) :4 , 0 , 0 , 1/n var (63) :3 , 0 , 0 , 1/n var (62) :2 , 0 , 0 , 1/n var (61) :1 , 0 , 0 , 1/n var (60) :0 , 0 , 0 , 1/n var (59) :4 , 3 , 2 , 0/n var (58) :3 , 3 , 2 , 0/n var (57) :2 , 3 , 2 , 0/n var (56) :1 , 3 , 2 , 0/n var (55) :0 , 3 , 2 , 0/n var (54) :4 , 2 , 2 , 0/n var (53) :3 , 2 , 2 , 0/n var (52) :2 , 2 , 2 , 0/n var (51) :1 , 2 , 2 , 0/n var (50) :0 , 2 , 2 , 0/n var (49) :4 , 1 , 2 , 0/n var (48) :3 , 1 , 2 , 0/n var (47) :2 , 1 , 2 , 0/n var (46) :1 , 1 , 2 , 0/n var (45) :0 , 1 , 2 , 0/n var (44) :4 , 0 , 2 , 0/n var (43) :3 , 0 , 2 , 0/n var (42) :2 , 0 , 2 , 0/n var (41) :1 , 0 , 2 , 0/n var (40) :0 , 0 , 2 , 0/n var (39) :4 , 3 , 1 , 0/n var (38) :3 , 3 , 1 , 0/n var (37) :2 , 3 , 1 , 0/n var (36) :1 , 3 , 1 , 0/n var (35) :0 , 3 , 1 , 0/n var (34) :4 , 2 , 1 , 0/n var (33) :3 , 2 , 1 , 0/n var (32) :2 , 2 , 1 , 0/n var (31) :1 , 2 , 1 , 0/n var (30) :0 , 2 , 1 , 0/n var (29) :4 , 1 , 1 , 0/n var (28) :3 , 1 , 1 , 0/n var (27) :2 , 1 , 1 , 0/n var (26) :1 , 1 , 1 , 0/n var (25) :0 , 1 , 1 , 0/n var (24) :4 , 0 , 1 , 0/n var (23) :3 , 0 , 1 , 0/n var (22) :2 , 0 , 1 , 0/n var (21) :1 , 0 , 1 , 0/n var (20) :0 , 0 , 1 , 0/n var (19) :4 , 3 , 0 , 0/n var (18) :3 , 3 , 0 , 0/n var (17) :2 , 3 , 0 , 0/n var (16) :1 , 3 , 0 , 0/n var (15) :0 , 3 , 0 , 0/n var (14) :4 , 2 , 0 , 0/n var (13) :3 , 2 , 0 , 0/n var (12) :2 , 2 , 0 , 0/n var (11) :1 , 2 , 0 , 0/n var (10) :0 , 2 , 0 , 0/n var (9) :4 , 1 , 0 , 0/n var (8) :3 , 1 , 0 , 0/n var (7) :2 , 1 , 0 , 0/n var (6) :1 , 1 , 0 , 0/n var (5) :0 , 1 , 0 , 0/n var (4) :4 , 0 , 0 , 0/n var (3) :3 , 0 , 0 , 0/n var (2) :2 , 0 , 0 , 0/n var (1) :1 , 0 , 0 , 0/n var (0) :0 , 0 , 0 , 0/n

相關文章
相關標籤/搜索