青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

huaxiazhihuo

 

玩具代碼 24點游戲

        所謂24點,就是甩出幾個整數,整數之間沒有固定的前后順序,給它們添加上加減乘除括號等,形成一條式子,最后運算結果等于24。很自然的想法,就是祭出表達式樹。但24點只是一個小程序,用表達式樹來解決,實在有點大材小用了,太委屈表達式樹了,所以堅決抵制。
        瀏覽各網友們的24點文章,發現大多數都在用最笨拙的窮舉法寫程序,或者是先搞成字符串,然后再對字符串求值,毫無新意,代碼風格也差,都是四五重循環,難以擴充。用窮舉法也沒什么不好,但是,就算是窮舉,也要窮舉得漂漂亮亮,雖不能遺漏,但也不要重復,然后代碼中也不能寫死了,要保持一定的擴充性。不過得承認,不管怎么樣,他們終究還是寫出了24點的代碼。
        24點粗看起來似乎有點棘手。但很容易就可以發現一種很自然的方法,假如4個整數參與24點了,那么就從中取出兩個數,進行加減乘除之后合成一個數,放回去,于是4個數變成3個數,再用同樣的辦法使這每一排3個數的組合變成兩個數,最后就只剩下兩個數,稍一運算,很容易就可以判斷兩個數能否湊成24。很容易就看得出來,這屬回溯法,最適合寫成遞歸的形式。但是,這一次的遞歸,要用代碼表達出來,卻著實有點不容易。不過,只要有了算法,總是有辦法寫成代碼。為了加深難度,也為效率,我也不打算在代碼中用到遞歸。
        一般來說,回溯法屬深度優先搜索法,它從問題領域中選取一個狀態作為當前節點,進行某一種運算之后,形成下一級的狀態,作為節點,再進行某種運算,再形成下下級的狀態,作為根據地,再嘗試新的節點,直到沒有可用的節點了,稱為葉子,就判斷此時的狀態是否滿足問題的解。不滿足,退回父節點,進行運算,進入下一級的狀態,繼續深度搜索。如果父節點無法進入新的狀態,那么只好退回祖父節點,進行同樣的操作。所以回溯算法的關鍵,在于新狀態的運算代碼,和各級節點的保存恢復代碼。
        再看看24點的問題,為便于行文,假設只有4個數參與運算。先來考察第一級狀態的節點數量。首先,從4個數中任意取出兩個數,共有C(4,2) = 6 種組合,兩個數a和b,利用加減乘除和交換位置,可以湊出6個結果,分別為a+b,a*b,b-a,a/b,a-b,b/a。于是,第一級狀態就有36節點。同理類推,第二級狀態有C(3,2)*6,第三級狀態有C(2,2)*6,沒有第四級了,第三級的節點,全部都是葉子,都要判斷。這意味著,24點算法中,存在36*18*6片葉子需要判斷。此外,24點中,4個數的狀態級數為3,可以預料到24點中狀態的級數比輸入參數的數目少1,你應該知道WHY的。
        由以上分析可知,每一級的狀態,由3個參數決定,分別是第1個數a、第2個數b和運算符號。運算符號取值范圍為0-5,分別表示a+b,a-b,a*b,a/b,b-a,b/a這6種運算。這3個參數是一個整體,代碼中用Step來表示,分別為nFst,nSnd,nOper。
……
        忽略了思考過程,下面簡單說明代碼結構。CGame24是主類,用以玩出24點游戲的解。其成員函數CalcNextResult()在內部狀態中用輸入的數構造出一個最終的表達式,這個表達式可能是正確的解,也可能不是。而Play()則通過調用不停地調用CalcNextResult()以嘗試得到一個正確的解。Express()則將表達式表示成字符串的形式。m_Nums用以儲存原始的輸入數據和中間運算結果,其中最后的一個數為表達式的最終運算結果。m_Flags用以指示m_Nums中的數是否已參與表達式中,以阻止同一個數多次進入表達式中。
        于是Step中的nFst,nSnd為m_Nums中的數的索引,很明顯,由于是組合關系,所以nSnd必將大于nFst。Step中還有一個nNext的變量,指向的是nSnd的下一個可用的索引,當nOper為最后一種運算時,nSnd就要進入到下一個位置了,也就是被賦予nNext的值。如果nNext沒有可用的值時,就表示要改變nFst的下標了。本來nNext的出現是為了將代碼寫得好看一點而硬造出來的一個變量,但不料在后面,卻發揮了很重要的作用,簡直是假如沒有它,代碼就沒法編了。
        整片程序的壓力全在Step::ToNext()上,它所做的事情,不過是為了使狀態進入下一個狀態中。但是其實現,卻異常復雜,要考慮組合的各種可能的情況,甚至還要考慮除數是否為0。承擔了太多的職責,但是我也想不出更好的方式,也不打算再思考了。
        好吧,我也承認代碼寫得異常糟糕,不過,這只是玩具代碼,原本就不愿精雕細刻,它還存在好多不足之處,比如輸出結果中,有時會加入多余的括號,這個問題還能解決。然后,它還不夠智能,遍歷出來的一些解,其本質上看還是相同,這個的解決就很有點難度了。此外,按抽象的觀點來看,回溯算法其實相當于一個容器,它的循環遍歷葉子節點或者解,可看成迭代器,這種思路,完全可以表達成C++的代碼等等。如果讀者愿意優化,請將優化后的結果發給在下,在下也很想瞅瞅。其實,我想說的是,就算老夫親自操刀,也不見得就勝過一眾宵小了,慚愧。
        算法這東西,現實中用得很少,高效復雜的算法自然有人在研究,我們只要注意將代碼寫得清晰一點就好了。不過,話又說回來,經過各種算法狂轟濫炸后的大腦,編出來的代碼,貌似比沒有經過算法折磨過的人,似乎總是要強一點。
#include <stdio.h>
#include 
<math.h>
#include 
<assert.h>
#include 
<utility>
#include 
<iostream>

using namespace std;

unsigned 
int gcd(unsigned int x, unsigned int y)   
{   
    unsigned  
int  nTimes=0;   
    
for (; 0 == (x&1&& 0 == (y&1); x>>=1, y>>=1)
        
++nTimes;

    
if (x < y)
        swap(x, y);

    
while (y > 0)
    
{
        
for (; 0 == (x & 1 );x >>= 1 )
            ;   

        
if (x < y)
            swap(x, y);
        x 
-= y;
        
if (x < y)
            swap(x, y);
    }

    
return x << nTimes;
}
 


class CRational
{
public:
    CRational(
int nNumberator=0int nDenominator=1)
        : m_nNum(nNumberator), m_nDe(nDenominator)
    
{
        assert(nDenominator 
!= 0);
        standarlize();
    }

    
int Numberator()const return m_nNum;}
    
int Denominator()const return m_nDe;}

    CRational
& operator+=(const CRational& _Right)
    
{
        m_nNum 
= m_nNum*_Right.m_nDe + _Right.m_nNum*m_nDe;
        m_nDe 
*= _Right.m_nDe;
        standarlize();
        
return *this;
    }


    CRational
& operator-=(const CRational& _Right)
    
{
        m_nNum 
= m_nNum*_Right.m_nDe - _Right.m_nNum*m_nDe;
        m_nDe 
*= _Right.m_nDe;
        standarlize();
        
return *this;
    }


    CRational
& operator*=(const CRational& _Right)
    
{
        m_nNum 
*= _Right.m_nNum;
        m_nDe 
*= _Right.m_nDe;
        standarlize();
        
return *this;
    }


    CRational
& operator/=(const CRational& _Right)
    
{
        assert(_Right.Denominator() 
!= 0);
        m_nNum 
*= _Right.m_nDe;
        m_nDe 
*= _Right.m_nNum;
        standarlize();
        
return *this;
    }


private:
    
void standarlize()
    
{
        
if (m_nDe < 0)
        
{
            m_nDe 
= -m_nDe;
            m_nNum 
= -m_nNum;
        }

        
int nGcd = gcd(abs(m_nNum), m_nDe);
        m_nNum 
/= nGcd;
        m_nDe 
/= nGcd;
    }

    
int m_nNum;
    
int m_nDe;
}
;

ostream
& operator << (ostream& outconst CRational& rat)
{
    cout 
<< rat.Numberator();
    
if (rat.Denominator() != 1)
        cout 
<< "/" << rat.Denominator();
    
return out;
}


CRational 
operator-(const CRational& _Left, const CRational& _Right)
{
    CRational _Tmp(_Left);
    
return _Tmp -= _Right;
}


CRational 
operator+(const CRational& _Left, const CRational& _Right)
{
    CRational _Tmp(_Left);
    
return _Tmp += _Right;
}


CRational 
operator*(const CRational& _Left, const CRational& _Right)
{
    CRational _Tmp(_Left);
    
return _Tmp *= _Right;
}


CRational 
operator/(const CRational& _Left, const CRational& _Right)
{
    CRational _Tmp(_Left);
    
return _Tmp /= _Right;
}


bool operator==(const CRational& _Left, const CRational& _Right)
{
    
return _Left.Numberator()==_Right.Numberator() && _Left.Denominator()==_Right.Denominator();
}


enum OperType{ OPER_ADD, OPER_SUB1, OPER_MUL, OPER_DIV1, OPER_SUB2, OPER_DIV2};

const char* g_sOPER_SYMBOL = "+-*/-/";
class CGame24
{
public:
    CGame24(
int nRes, int* pNums, int nLen);

    
bool Play();
    
bool CalcNextResult();
    size_t Express(
char* pExp);

private:
    
struct Step
    
{
        
char nOper;
        
char nFst;
        
char nSnd;
        
char nNext;

        
void ToNext(bool* pFlags, const CRational* pNums, int nMax);

        
bool HasNext(const bool* pFlags, int nMax)
        
{
            
if (nNext >= nMax)
            
{
                
int nCount = 0;
                
for (char i = nFst+1; i < nSnd && nCount<2; i++)
                
{
                    
if (!pFlags[i])
                        nCount
++;
                }

                
return nCount == 2;
            }

            
return true;
        }


        
void Discard(bool* pFlags)
        
{
            pFlags[nFst] 
= false;
            pFlags[nSnd] 
= false;
            nFst 
= 0;
            nSnd 
= 0;
            nNext 
= 0;
        }

    }
;

    size_t buildExpress(
char* pExp, char nStep, char nSuperOper);

    
enum {_nSIZE = 100};
    CRational m_Nums[_nSIZE
*2];
    
bool m_Flags[_nSIZE*2];
    Step m_Steps[_nSIZE];
    
int m_nRes;
    
char m_nLen;
    
char m_nCur;
}
;

void CGame24::Step::ToNext(bool* pFlags, const CRational* pNums, int nMax)
{
    assert(HasNext(pFlags, nMax));
    
if (nNext == nMax)
    
{
        pFlags[nFst] 
= false;
        pFlags[nSnd] 
= false;
        nOper 
= 0;
        nNext 
= 0;
        nFst
++;
        nSnd 
= nFst;
    }

    
if (nFst >= nSnd)
    
{
        
for (; nFst<nMax-1 && pFlags[nFst]; nFst++)
            ;
        nOper 
= 0;
        pFlags[nFst] 
= true;
        nSnd 
= nFst;
        
for (nNext = nFst+1; nNext<nMax && pFlags[nNext]; nNext++)
            ;
        assert (nNext 
!= nMax);
    }


    
if (nNext > nSnd)
    
{
        assert(
!pFlags[nNext]);
        
if (nSnd != nFst)
            pFlags[nSnd] 
= false;
        nSnd 
= nNext;
        pFlags[nSnd] 
= true;
        nOper 
= 0;
        
return;
    }

    nOper
++;
    
if (nOper==OPER_DIV1 && pNums[nSnd].Numberator()==0)
        nOper
++;
    
char nNextOper = nOper+1;
    
if (nNextOper>OPER_MUL)
    
{
        
if (nNextOper == OPER_DIV1 && pNums[nSnd].Numberator()==0)
            nNextOper
++;
        
if (nNextOper == OPER_DIV2 && pNums[nFst].Numberator()==0)
            nNextOper
++;
    }


    
if (nNextOper > OPER_DIV2)
    
{
        
for (nNext=nSnd+1; nNext<nMax && pFlags[nNext]; nNext++)
            ;
    }

}


CRational OperateRationals(
const CRational& fst, const CRational& snd, char nOper)
{
    
switch (nOper)
    
{
    
case OPER_ADD: return fst + snd; 
    
case OPER_SUB1: return fst - snd; 
    
case OPER_SUB2: return snd - fst; 
    
case OPER_MUL: return fst * snd; 

    
case OPER_DIV1: 
        assert (snd.Numberator() 
!= 0);
        
return fst/snd;

    
case OPER_DIV2: 
        assert (fst.Numberator() 
!= 0);
        
return snd/fst;
    }

    assert (
false);
    
return 0;
}


CGame24::CGame24(
int nRes, int* pNums, int nLen)
{
    assert(nLen 
> 0 && nLen < _nSIZE);
    m_nRes 
= nRes;
    
for (int i=0; i<nLen; i++)
        m_Nums[i] 
= pNums[i];
    memset(m_Flags, 
0sizeof(m_Flags));
    memset(m_Steps, 
0sizeof(m_Steps));
    m_nLen 
= static_cast<char>(nLen);
    m_nCur 
= 0;
}


bool CGame24::CalcNextResult()
{
    
while (m_nCur >= 0 && !m_Steps[m_nCur].HasNext(m_Flags, m_nLen+m_nCur))
        m_Steps[m_nCur
--].Discard(m_Flags);
    
if (m_nCur < 0)
        
return false;

    
while (m_nCur < m_nLen-1)
    
{
        m_Steps[m_nCur].ToNext(m_Flags, m_Nums, m_nLen
+m_nCur);
        
const Step& step = m_Steps[m_nCur];
        m_Nums[m_nLen
+m_nCur] = OperateRationals(m_Nums[step.nFst], m_Nums[step.nSnd], step.nOper);
        m_nCur
++;
    }

    m_nCur
--;

    
return true;
}


bool CGame24::Play()
{
    
while (CalcNextResult())
    
{
        
if (m_Nums[m_nLen+m_nCur] == m_nRes)
            
return true;
    }

    
return false;
}


size_t CGame24::Express(
char* pExp)
{
    size_t len 
= buildExpress(pExp, m_nCur, OPER_ADD); // 加法的運算級別最低
    pExp[len] = 0;
    
return len;
}


bool NeedParentheses(char nSuperOper, char nSubOper)
{
    assert(nSuperOper 
<= OPER_DIV2);
    assert(nSubOper 
<= OPER_DIV2);
    
static const char g_ACTUAL_OPER[] = {OPER_ADD, OPER_SUB1, OPER_MUL, OPER_DIV1, OPER_SUB1, OPER_DIV1};
    nSuperOper 
= g_ACTUAL_OPER[nSuperOper];
    nSubOper 
= g_ACTUAL_OPER[nSubOper];
    
return (nSuperOper>nSubOper) || (nSuperOper==nSubOper && (nSubOper==OPER_SUB1 || nSuperOper==OPER_DIV1));
}


size_t CGame24::buildExpress(
char* pExp, char nStep, char nSuperOper)
{
    assert(nStep 
<= m_nCur);
    
char* sPos = pExp;
    
const Step& step = m_Steps[nStep];
    
char nFst = step.nFst;
    
char nSnd = step.nSnd;
    
char nOper = step.nOper;
    
if(step.nOper==OPER_SUB2 || step.nOper==OPER_DIV2)
        swap(nFst, nSnd);

    
bool bParentheses = NeedParentheses(nSuperOper, nOper);
    
if (bParentheses)
        
*sPos++ = '(';
    
if (nFst >= m_nLen)
        sPos 
+= buildExpress(sPos, nFst-m_nLen, nOper);
    
else
        sPos 
+= sprintf(sPos, ("%d"), m_Nums[nFst].Numberator());

    
*sPos++ = g_sOPER_SYMBOL[nOper];

    
if (nSnd >= m_nLen)
        sPos 
+= buildExpress(sPos, nSnd-m_nLen, nOper);
    
else
        sPos 
+= sprintf(sPos, ("%d"), m_Nums[nSnd].Numberator());

    
if (bParentheses)
        
*sPos++ = ')';
    
return sPos-pExp;
}


int main()
{
    
char sExpress[256= 0 };
    
int Nums[] = {12345};
    CGame24 game(
24, Nums, 5);
    
while (game.Play())
    
{
        game.Express(sExpress);
        cout 
<< sExpress << endl;
    }

    
return 0;
}

posted on 2012-06-07 16:20 華夏之火 閱讀(1883) 評論(1)  編輯 收藏 引用 所屬分類: 玩具代碼

評論

# re: 玩具代碼 24點游戲 2012-06-15 14:29 ss

可以運行嗎  回復  更多評論   

導航

統計

常用鏈接

留言簿(6)

隨筆分類

隨筆檔案

搜索

積分與排名

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国内视频一区| 榴莲视频成人在线观看| 欧美性一二三区| 亚洲免费在线视频| 亚洲一区二区动漫| 国产欧美三级| 欧美成人蜜桃| 欧美日韩另类一区| 欧美自拍偷拍| 欧美成人一区二区三区| 亚洲视频图片小说| 欧美一区二区三区免费视频| 影音欧美亚洲| 一本到高清视频免费精品| 国产精品综合色区在线观看| 另类天堂av| 欧美午夜激情在线| 免费观看一级特黄欧美大片| 欧美日本在线| 久久三级视频| 欧美性大战久久久久久久| 久久女同精品一区二区| 欧美精品一区在线发布| 久久成人精品视频| 欧美日韩成人在线播放| 久久久噜噜噜久久久| 欧美另类高清视频在线| 久久久久久亚洲精品不卡4k岛国| 欧美成人综合网站| 欧美一区二区在线观看| 欧美精品九九99久久| 久久久91精品国产一区二区三区| 欧美成人精品在线| 久久久久久久一区二区| 欧美日韩免费在线视频| 免费成人激情视频| 国产女主播一区二区| 99av国产精品欲麻豆| 亚洲高清视频在线观看| 午夜欧美不卡精品aaaaa| 宅男精品视频| 欧美精品免费看| 免费成人毛片| 激情亚洲一区二区三区四区| 亚洲性夜色噜噜噜7777| 一区二区三区 在线观看视频| 久久全国免费视频| 久久视频在线免费观看| 国产伦精品一区二区三区高清版| 亚洲精品美女久久久久| 激情综合色综合久久| 午夜精品一区二区三区在线视| 一本色道久久综合亚洲精品按摩| 毛片基地黄久久久久久天堂| 裸体素人女欧美日韩| 狠狠色丁香婷婷综合久久片| 亚洲欧美一区二区视频| 亚洲淫性视频| 亚洲理论在线| 欧美精品一区二区三区高清aⅴ| 久久人人97超碰人人澡爱香蕉| 国产精品国产三级欧美二区 | 国产精品一卡二| 一二三区精品| 亚洲欧美日韩爽爽影院| 国产精品www994| 亚洲一区二区免费看| 欧美一区2区三区4区公司二百 | 久久综合久久综合久久| 欧美成人网在线| 亚洲激情在线视频| 欧美国产一区视频在线观看| 亚洲日韩第九十九页| 一区二区激情| 国产精品色在线| 欧美在线视频导航| 欧美不卡一卡二卡免费版| 亚洲七七久久综合桃花剧情介绍| 欧美激情亚洲一区| 一区二区黄色| 久久久久久网| 一本久道久久综合婷婷鲸鱼| 国产精品国产三级国产普通话三级 | 欧美日韩精品一区视频 | 久久―日本道色综合久久| 亚洲国产精品日韩| 欧美三级午夜理伦三级中视频| 亚洲专区一区二区三区| 六十路精品视频| 一区二区三区福利| 国产在线国偷精品产拍免费yy| 老司机67194精品线观看| 99re热这里只有精品视频| 欧美中文字幕视频| 亚洲精品欧美极品| 国产精品午夜在线观看| 久久综合久色欧美综合狠狠| 99re热这里只有精品免费视频| 久久精品免费观看| 亚洲作爱视频| 精品91免费| 国产精品红桃| 欧美电影电视剧在线观看| 亚洲欧美日韩在线综合| 91久久久久久国产精品| 久久精品视频免费播放| 99国内精品久久| 激情久久综艺| 国产精品午夜在线观看| 欧美日本久久| 乱人伦精品视频在线观看| 亚洲自拍偷拍福利| 亚洲免费不卡| 亚洲国产高清aⅴ视频| 久久久国产精品亚洲一区 | 亚洲欧美国产日韩中文字幕| 亚洲国产三级| 狠狠色狠狠色综合日日91app| 欧美激情小视频| 亚洲成人影音| 国产亚洲欧美一区| 欧美性大战xxxxx久久久| 欧美国产专区| 免费久久99精品国产| 久久国产精品久久精品国产 | 久久久之久亚州精品露出| 午夜精品久久久久99热蜜桃导演| 亚洲啪啪91| 亚洲电影免费在线| 一区二区三区在线视频免费观看 | 欧美精品一区二区高清在线观看| 久久精品成人一区二区三区蜜臀 | 亚洲伦伦在线| 亚洲精品一区在线观看| 91久久久在线| 最近中文字幕日韩精品| 欧美激情亚洲综合一区| 欧美成熟视频| 亚洲高清免费| 亚洲国产精品一区二区www在线 | 亚洲国产精品激情在线观看| 欧美大片一区二区三区| 欧美1区3d| 亚洲高清视频在线| 亚洲黑丝在线| 亚洲免费成人av| 亚洲网站在线看| 亚洲欧美日韩国产中文 | 夜夜嗨av一区二区三区四季av| 日韩一级在线观看| 亚洲桃色在线一区| 羞羞视频在线观看欧美| 久久国产主播| 麻豆成人在线观看| 欧美另类高清视频在线| 欧美新色视频| 国产亚洲欧美在线| 亚洲电影视频在线| 亚洲最新在线视频| 先锋影院在线亚洲| 久久婷婷av| 亚洲精品乱码久久久久| 亚洲香蕉成视频在线观看| 欧美一级黄色网| 免费观看成人| 欧美午夜性色大片在线观看| 国产欧美丝祙| 亚洲精品中文字幕女同| 午夜精品成人在线| 理论片一区二区在线| 亚洲黄色片网站| 午夜精品www| 欧美不卡在线视频| 国产伦精品一区二区三区高清| 亚洲国产精品999| 亚洲无限av看| 欧美mv日韩mv国产网站app| 一个色综合导航| 久久久久国产精品www| 欧美二区在线看| 国内精品久久久久久久影视蜜臀 | 欧美日韩久久| 国产综合久久| 亚洲尤物视频网| 欧美国产成人在线| 亚洲欧洲99久久| 欧美精品少妇一区二区三区| 国产一区二三区| 亚洲一区国产精品| 亚洲国产美女精品久久久久∴| 黄色小说综合网站| 亚洲欧美成人| 欧美v日韩v国产v| 亚洲欧美日韩国产成人| 欧美精品一区二区三| 亚洲高清视频在线| 久久久久中文| 欧美在线免费视频| 国产精品影院在线观看| 亚洲小说欧美另类社区|