• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            雁過無痕

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::

            《編程之美》讀書筆記22:    1.16  24點(diǎn)游戲

            給定4個數(shù),能否只通過加減乘除計算得到24?由于只有4個數(shù),弄個多重循環(huán),就可以。如果要推廣到n個數(shù),有兩種思路:

            采用前綴/后綴表達(dá)式。相當(dāng)于將n個數(shù)用n-1個括號括起來,其數(shù)目就是一個catlan數(shù)。最多可得到 f(n) = (1/n * (2*n - 2)! / (n-1)! / (n-1)!) * n! * 4^(n-1) = 4^(n-1) * (2*n-2)! / (n-1)! 種表達(dá)式,當(dāng)n=4時,共可得到 7680種。

            n個數(shù)中任意抽取2個,進(jìn)行計算最多有6種結(jié)果,將計算結(jié)果放回去,再從剩下的n-1個任取2個,進(jìn)行計算,如此反復(fù),直到只剩下1個數(shù)。按這種算法,共要處理表達(dá)式:g(n)=(n*(n-1)/2*6) * ((n-1)*(n-2)/2*6) * ((n-2)*(n-3)/2*6) * (2*1/2*6) = n!*(n-1)!*3^(n-1)當(dāng)n=4時,最多要處理3888種。 (書上的代碼將這兩種思路混在一塊了。)

            f(n) / g(n) = (4/3)^(n-1) * (2*n-2)! / n! / (n-1)! / (n-1)!

            很明顯,當(dāng)n比較大時(比如n大于8),會有 f(n) < g(n)。比如:f(10)/g(10)=0.178

            f(n)g(n)的比值,可以看出,這兩種解法都存在大量的不必要計算。當(dāng)n比較大時,思路2的冗余計算已經(jīng)嚴(yán)重影響了性能。要如何減少這些不必要計算呢?

            可以記錄得到某個計算結(jié)果時所進(jìn)行操作。比如: abcd4個數(shù)取前2個,進(jìn)行加法計算得到 a+b,則記錄‘+’。另外,假設(shè)加減號的優(yōu)先級為0,乘除號的優(yōu)先級為1

            ab進(jìn)行減/除計算時,實(shí)際上得到 a-bb-aa/bb/a

            當(dāng)取出2個數(shù)ab,進(jìn)行計算,這兩個數(shù)上次的操作符有下面這幾種情況:

            都為空:

            要計算6個結(jié)果,即 a+b, a-b, b-a, a*b, a/b, b/a

             

            只有一個為空:假設(shè): a = a1 op1 a2

               ⑴ 一種剪枝方法是: op1為減(除)號,則不進(jìn)行加減(乘除)計算。

                   因?yàn)椋?/span> (a-b)-c可以轉(zhuǎn)為a-(b+c),這兩個表達(dá)式只要計算一個就可以。

             

            ⑵ 另一種剪枝方法:額外記錄每次計算最靠后的那個數(shù)的位置。比如位置順序:abcd,進(jìn)行a+c計算時,記錄了c位置,再與數(shù)b計算時,由于b位置在c位置前,不允許計算 (a+c) + b (a+c) – b這樣就避免了表達(dá)式 a+b+c a-b+c被重復(fù)計算。

             

            都不為空: 假設(shè): a = a1 op1 a2 b= b1 op2 b2

               要計算的結(jié)果: a op3 b = a1 op1 a2op3 (b1 op2 b2)

               ⑴ 如果 op1 op2的優(yōu)先級相同,那么 op3 的優(yōu)先級不能與它們相同,若相同,則原來的表達(dá)式可以轉(zhuǎn)為 ((a1 op4 a2) op5 b1) op6 b2,因而沒必要對原來的表達(dá)式進(jìn)行計算。比如 (m1+m2)(m3-m4)之間只進(jìn)行乘除計算,而不進(jìn)行加減計算。

            ⑵ 如果 op1 op2的優(yōu)先級不同,那么 op3 無論怎么取,其優(yōu)先級都必會與其中一個相同,則原表達(dá)式可以轉(zhuǎn)化((c1 op4 c2) op5 c3) op6 c4這種形式,因而該表達(dá)式?jīng)]必要計算。如(m1+m2)(m3*m4),不進(jìn)行任何計算。

            總之:op1 op2優(yōu)先級不同時,不進(jìn)行計算。

                     op1 op2優(yōu)先級相同時,進(jìn)行計算的操作符優(yōu)先級不與它們相同。

             

            要注意的是:剪枝不一定提高性能(在筆記1.3 一摞烙餅的排序 中已經(jīng)說明了這個問題)。如果n個數(shù)計算可得到24,過多的避免冗余計算,有可能嚴(yán)重降低性能。計算n=6時,碰到一個組合,僅使用了③的剪枝方法,得到結(jié)果時處理了四百個表達(dá)式,但再采用了②的第一種剪枝方法,處理的表達(dá)式達(dá)到五十三萬多。(也許②的第二種剪枝方法不存在這么嚴(yán)重的問題。)與烙餅排序不同的是,烙餅排序總能找到一個結(jié)果,而n個數(shù)計算有可能無解。顯然在無解時,采用盡可能多的剪枝方法,必然會極大的提高性能。

             

            另外,對于輸出表達(dá)式,書上的程序進(jìn)行了大量的字符串操作,實(shí)際上可以只記錄,每一步取出的兩個數(shù)的位置(即記錄ij值),在需要輸出時,再根據(jù)所記錄的位置,進(jìn)行相應(yīng)的字符串操作就可以了。

             

            書上的解法二實(shí)現(xiàn)



            下面的代碼是個半成品:




            #include
            <iostream>
            #include
            <sstream>
            #include
            <cmath>
            using namespace std;

            const double Result = 24;
            const size_t Cards = 6;
            double number[Cards]={11,21,31,41,51,61};
            char op[Cards+1= {0};
            size_t pos[Cards];

            static long long count1=0;
            static long long count2=0;
            static bool calc(size_t step);

            inline 
            bool calc2(size_t step, size_t i, double na, double nb, char op9)
            {
              op[i] 
            = op9;
              
            switch (op9) {
                
            case '+':   number[i] = na + nb; break;
                
            case '-':   number[i] = na - nb; break;
                
            case '*':   number[i] = na * nb; break;
                
            case '/':   number[i] = na / nb; break;
                
            default : break;
              }

              
            return calc(step-1);
            }


            inline 
            bool iszero(double num)
            {
              
            const double Zero = 1e-9
              
            if (num > Zero || num < -1.0 * Zero) return false
              
            return true;
            }


            size_t getop(
            const char op9)
            {
              
            static size_t arr[256]= {0}
              arr[
            '+']=1,arr['-']=1,arr['*']=4,arr['/']=4;
              
            return arr[(size_t)op9];
            }



            bool calc(size_t step)
            {
              
            ++count1;
              
            if (step <= 1{
                
            ++count2;   
                
            if (fabs(number[0- Result)<1e-6{
                  
            return true
                }
              
                
            return false;
              }
             
              
            for(size_t i = 0; i < step; i++){
                
            for(size_t j = i + 1; j < step; j++{
                  
            double na = number[i];
                  
            double nb = number[j];
                  unsigned 
            char op1=op[i];
                  unsigned 
            char op2=op[j];
                  op[j] 
            = op[step - 1];
                  number[j] 
            = number[step - 1];
                  
            bool ba=true, bb=true;
                  size_t v
            =getop(op1)+getop(op2);
                  
                  
            if (v==5) ba=bb=false;
                  
            else if (v==2) ba=false;
                  
            else if (v==8) bb=false;
                  
            // else if (v==1 || v==4) {
                    
            // unsigned char ch2= op1 + op2;      
                    
            // if (ch2=='-') ba=false;
                    
            // else if (ch2=='/') bb=false;
                  
            // } 
                
                   
                  
            //if (v==5) ba=bb=false;
                  
            // else if (((v-1)&v)==0) { //case: 1 2 4 8
                    
            // if (v==2) ba=false;
                    
            // else if (v==8) bb=false;
                    
            // else {
                      
            // unsigned char ch2= op1 | op2;      
                      
            // if (ch2=='-') ba=false;
                      
            // else if (ch2=='/') bb=false;          
                    
            // }   
                  
            // }   
                  
                  
            //if (1) ba=bb=true;         
                  if (ba) {
                    
            if (calc2(step, i, na, nb, '+')) return true;
                    
            if (calc2(step, i, na, nb, '-')) return true;
                    
            if (calc2(step, i, nb, na, '-')) return true;
                  }

                  
            if (bb) {
                    
            if (calc2(step, i, na, nb, '*')) return true;
                    
            if (! iszero(nb) && calc2(step, i,na, nb, '/')) return true;
                    
            if (! iszero(na) && calc2(step, i,nb, na, '/')) return true
                  }
             
                 
                  number[i] 
            = na;
                  number[j] 
            = nb;
                  op[i] 
            = op1;
                  op[j] 
            = op2;     
                }

              }

              
            return false;
            }


            int main()
            {
              
            for (size_t i=0; i<Cards; ++i) pos[i]=i;
              cout
            << calc(Cards)<<endl;
              cout
            << count1<<"  "<<count2<<endl; 
            }


            posted on 2010-08-01 22:50 flyinghearts 閱讀(1008) 評論(0)  編輯 收藏 引用 所屬分類: 編程之美C++
            久久99国产一区二区三区| 久久精品亚洲精品国产欧美| 亚洲伊人久久精品影院| 伊人久久大香线蕉综合Av| 伊人久久大香线蕉综合影院首页| 精品免费久久久久久久| 日韩精品久久久久久| 久久精品国产亚洲Aⅴ香蕉| 要久久爱在线免费观看| 伊人色综合久久天天人手人婷 | 9999国产精品欧美久久久久久| 国产精自产拍久久久久久蜜| 久久这里的只有是精品23| 亚洲国产精品久久久天堂| 欧美777精品久久久久网| 久久只这里是精品66| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 国产综合免费精品久久久| 色播久久人人爽人人爽人人片AV| 新狼窝色AV性久久久久久| 欧美久久综合性欧美| 国内精品伊人久久久影院 | 亚洲AV日韩精品久久久久| 四虎国产精品免费久久久| 国产69精品久久久久9999APGF| 91久久精品电影| 久久亚洲精品人成综合网| 久久久青草青青国产亚洲免观| 日韩精品久久久久久久电影蜜臀| 国产精品狼人久久久久影院| 日韩乱码人妻无码中文字幕久久 | 99久久精品国产一区二区| 亚洲精品无码久久久影院相关影片 | 久久99精品九九九久久婷婷| 亚洲AV无码1区2区久久 | 人妻少妇精品久久| 久久久精品一区二区三区| 亚洲欧美日韩久久精品第一区| 污污内射久久一区二区欧美日韩| 久久久精品一区二区三区| 久久亚洲精品无码AV红樱桃|