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

隨筆 - 51, 文章 - 1, 評論 - 41, 引用 - 0
數據加載中……

猜數字的一種解法

         本文將給出解答猜數字游戲(guess number)的一種算法,最多6步就可猜出結果。這個的解法需要用到部分信息論的知識
    猜數字問題表述如下:答案是09十個數的四位排列(沒有重復元素)。每猜一次,游戲比較答案和輸入這兩組排列,反饋aAbBaA表示有a個數字數值正確位置正確,bB表示b個數字數值正確位置錯誤。
    考慮問題的互動方式,這道題目屬于輸入反饋的問題。每次輸入,從反饋中獲取部分信息,當獲得系統的全部信息時,就能猜出答案。所以解這個問題的關鍵是尋找合適的輸入使反饋的信息量最大。
    這道題的解法思路比較簡單,由于是有窮狀態,而且數量不大,可用窮舉法解答。比較所有可能的輸入,找出最佳輸入(某個標準下)。問題變成了如何衡量輸入的好壞。輸入越好則反饋的信息越大,山農給出的信息量的定義是衡量輸入好壞的標準。信息量是不確定性的大小,如果某個事件的概率為P,則它含有的信息量為log(1/P)。具體的理論可以參考一本關于信息論的書。
    具體到猜數字這個題目,答案有多種可能。得到反饋前,每一個輸入的反饋有不同的可能。得到反饋后,反饋是確定的,不確定性變為0。這樣問題的信息量變小了。前后的信息量之差就是這個輸入能夠得到的信息量。

統計反饋前這個輸入可能得到的反饋,求出各種反饋的概率,可由下面公式計算出反饋前的信息量:
H=P1*log(1/P1)+P2*log(1/P2)+...P1P2等分別為不同反饋的概率。
反饋后,這個輸入的反饋是確定的,信息量為0比較所有輸入能夠得到信息量,就能找出最佳的輸入。

統計反饋前這個輸入可能得到的反饋

// 把輸入和所有可能的答案比較,得到所以不同反饋可能出現的次數
// 輸入參數:input輸入
// 輸出參數:feedbacks反饋可能出現的次數
void GetPsbFeedbacksNum(VectorInt
& feedbacks, const VectorInt& input)
{
        
// 和所有可能的答案比較
    
for (int j=0; j<ALL_ANS_NUM; j++)
    {
        
// 答案是否已經被排除
        
if (g_AnsState[j] != 0)
            continue;
        feedbacks[GetFeedback(input, g_AllAns[j])]
++;
    }
}

計算這個輸入能夠獲得的信息量
// 計算信息量
// 輸入參數:不同反饋出現的次數
// 返回值:信息量
double CalcEntropy(const VectorInt &feedbacks)
{
    
int sum = 0;
    
double entropy = 0.;
    
for (int j=0; j<feedbacks.size(); j++)
        sum 
+= feedbacks[j];

    
for (int j=0; j<feedbacks.size(); j++)
    {
        
if (feedbacks[j] == 0)
            continue;
        float tmp 
= (float)feedbacks[j]/sum;
        entropy 
+= -1*tmp*log(tmp);
    }
    return entropy;
}

這樣就得到每個輸入的信息量。下面討論如何枚舉所有可能的輸入。
輸入的種類有10*9*8*7種,把每一種輸入和所有可能答案比較。這方法比較直觀,但運算次數太多。
// 得到最佳的輸入,不分類直接比較的方法
// 最佳輸入存放在g_AnsGuess中
void GetBestInputNoSort()
{
    
double max_entropy = 0.;    // 存放最大的信息量
    VectorInt feedbacks((ANS_SIZE
+1)*(ANS_SIZE+1), 0);    // 反饋的結果分類

    
// 比較所有輸入的信息量
    
for (int i=0; i<ALL_ANS_NUM; i++)
    {
        
// 這個輸入的信息量是否是0
        
if (g_InputState[i] == 1)
            continue;

        
// 是否只在可能的答案中搜索最佳輸入
//        if (g_AnsState[i] != 0)
//            continue;

        
// 得到所有可能的反饋
        feedbacks.assign((ANS_SIZE
+1)*(ANS_SIZE+1), 0);
        GetPsbFeedbacksNum(feedbacks, g_AllAns[i]); 

        
// 計算信息量
        
double entropy = CalcEntropy(feedbacks);

        
// 排除信息量為0的輸入
        
if (entropy < 0.00001)
        {
            g_InputState[i] 
= 1;
            continue;
        }

        
// 求最大的信息量
        
if (max_entropy < entropy)
        {
            max_entropy 
= entropy;
            g_AnsGuess 
= g_AllAns[i];
        }
    }    
}

由于第一次輸入,各種輸入能夠得到的信息量是一樣的,因此第一次可以不比較,任給一組輸出。改進后的代碼如下:
// 得到最佳的輸入,不分類直接比較的方法,但優化過第一次輸入。
// 最佳輸入存放在g_AnsGuess中
void GetBestInputIpvFst()
{
    
// 如果是第一次,所有輸入的信息量是一樣的,任選一個
    
if (g_isFirstTime)
    {
        g_isFirstTime 
= 0;
        g_AnsGuess 
= g_AllAns[0];
    }
    
else
        GetBestInputNoSort();
}

第一次輸入時10個元素之間是沒有分別的。沿著這個思路考慮,第二次輸入時,6個沒有參與輸入的元素,也沒有分別。舉例來說,第一次輸入{0,1,2,3},則4,5,6,7,8,9六個元素屬同一類元素,在第二次輸入時可以相互替換。如{0,1,2,4}和{0,1,2,5}兩組輸入能夠得到的信息量應該相同。把元素分類枚舉則可以優化算法。
分類方法如下,參入輸出的元素單獨成一類,沒有參與的元素是一類。第一次輸入時,只有一類元素,這類元素個數為10。第二次輸入時,有五類元素,有四類元素個數為1,一類元素個數為6。依次類推。關于如何枚舉見《從集合中枚舉子集》
// 得到最佳的輸入,元素分類的方法
// 最佳輸入存放在g_AnsGuess中
void GetBestInputSort()
{
    
double max_entropy = 0.;    // 存放最大的信息量
    VectorInt feedbacks((ANS_SIZE
+1)*(ANS_SIZE+1), 0);// 反饋的結果分類

    
// 初始化枚舉
    CSetIterAgent
<int> iter(g_AnsEle);
    iter.Init(ANS_SIZE, CSetIter::MULT_ORDERED_IN);

    
// 比較所有輸入的信息量
    VectorInt setsub(ANS_SIZE, 
0);
    
while (iter.GetNextSubset(setsub, g_AnsEle))
    {
        
// 把-1元素具體化,-1表示該元素沒有輸入過
        AssembleInput(setsub);

//        // 這個輸入的信息量是否是0
//        if (g_InputState[GetSetPosition(setsub)] == 1)
//            continue;

        
// 是否只在可能的答案中搜索最佳輸入
//        if (g_AnsState[GetSetPosition(setsub)] != 0)
//            continue;

        
// 得到所有可能反饋的數目
        feedbacks.assign((ANS_SIZE
+1)*(ANS_SIZE+1), 0);
        GetPsbFeedbacksNum(feedbacks, setsub);

        
// 計算信息量
        
double entropy = CalcEntropy(feedbacks);

//        // 排除信息量為0的輸入
//        if (entropy < 0.00001)
//        {
//            g_InputState[GetSetPosition(setsub)] = 1;
//            continue;
//        }

        
// 求最大的信息量
        
if (max_entropy < entropy)
        {
            max_entropy 
= entropy;
            g_AnsGuess 
= setsub;
        }
    }    
    
// 元素分類
    SortEle();
}

分類的方法可以大大提升運算速度,下面的測試會證明這一點。但當參與輸入元素慢慢增加時,分類就不那么重要,而且調用CSetIterAgent也是一筆不小的開銷。將第一種算法和分類法結合:
// 不分類法和分類法的混合法
// 輸入參數:num表示當輸入元素個數等于或超過num時用直接法
void GetBestInputBlend(
int num)
{
    
// 計算沒有輸入過的元素個數
    
int sum = 0;
    
for (int i=0; i<g_AnsEle.size(); i++)
    {
        
if (g_AnsEle[i] == -1)
            sum
++;
    }
    sum 
= g_AnsEle.size() - sum;

    
if (sum >= num)
        GetBestInputNoSort();
    
else
        GetBestInputSort();
}

下面給出這些算法的測試結果。測試方法是將10*9*8*7種答案依次用這些算法求解,統計猜出每個答案需要多少次數。一共花費了多少時間。
1次         1
2次         12
3次         261
4次         2082
5次         2500
6次         184
平均次數:4.51190
N次是指N次輸入反饋后,就可以確定答案,并不指第N次輸入的反饋是4A0B。
花費的時間:
GetBestInputNoSort:       8h也沒有算完
GetBestInputIpvFst:         9385s
GetBestInputSort:            1596s
GetBestInputBlend7:       2151s
GetBestInputBlend10:     1515s

這些方法在本質上是一樣的,即在所有的輸入中尋找反饋信息量最大的輸入。下面考慮其他方法,比較這些方法的差別。
如果縮小尋找范圍,不考慮不是答案的輸入。代碼如下:
取消GetBestInputNoSort函數中
        // 是否只在可能的答案中搜索最佳輸入
        
if (g_AnsState[i] != 0)
            continue;
和GetBestInputSort函數中
        // 是否只在可能的答案中搜索最佳輸入
        
if (g_AnsState[GetSetPosition(setsub)] != 0)
            continue;
這兩行注釋。
測試結果如下:
1次       1
2次       16
3次       228
4次       1555
5次       2688
6次       542
7次       10
平均次數:4.70218
運行時間:
GetBestInputIpvFst:1375s
GetBestInputSort:   97s
縮小范圍后,速度有很多提升,但平均次數增加了。

再考慮另外一種方法,不從信息量的角度考慮。用第一個可能為答案的排列作為輸入。
// 得到第一個可能的答案
void GetFstPsbInput()
{
    
for (int i=0; i<ALL_ANS_NUM; i++)
    {
        
if (g_AnsState[i] == 0)
        {
            g_AnsGuess 
= g_AllAns[i];
            break;
        }
    }
}
測試結果:
1次       1
2次       15
3次       211
4次       1240
5次       2108
6次       1203
7次       252
8次       10
平均次數:5.00515
花費的時間:7s
這個方法令人吃驚的是它的速度,如此簡單卻又不錯的效果。平均次數要比上面兩個方法差些。
上面的測試結果是在vc2005的release下編譯測試。

         本文用信息量大小作為判斷最佳輸入的標準,相比其他算法平均步數較少,但花費的時間較多。如何縮短計算時間將在以后的文章中繼續探討。此外從測試中看出,方法2,3在兩次內猜中答案的次數比方法1多。在這個意義下方法2,3比方法1要優。以后還會在不同的意義下比較各類算法。大家有什么好的想法可以聯系我,大家一起討論。我的郵箱lemene@sina.com.cn

代碼下載

posted on 2007-11-26 16:42 lemene 閱讀(5340) 評論(5)  編輯 收藏 引用

評論

# re: 猜數字的一種解法  回復  更多評論   

見過的最好結果6步
100%
2008-03-13 12:54 | QQ474073341

# re: 猜數字的一種解法  回復  更多評論   

我已經證明了六步不可能猜完所有的數
149588829
2008-03-13 14:46 | yczni

# re: 猜數字的一種解法[未登錄]  回復  更多評論   

可以六步完成,這里是指最多六步就知道確切的結果。不是指六步就反饋4A0B。有點細微的差別,如果一定要反饋4A0B才算成功,則需要七步。
2008-03-14 23:52 | lemene

# re: 猜數字的一種解法  回復  更多評論   

依靠反饋的熵的最大值來決定最佳猜測感覺沒有依據,我覺得應該是根據每種可能的反饋導致正確答案范圍的減小量來作為信息量比較合適。
2011-05-06 21:49 | 奔跑

# re: 猜數字的一種解法[未登錄]  回復  更多評論   

@奔跑
本算法基本思想也可以理解“根據每種可能的反饋導致正確答案范圍的減小量來作為信息量”,具體的算法只是這一思想的數學建模。
2011-05-07 17:52 | lemene
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            99精品国产热久久91蜜凸| 99精品免费| 久久精品中文字幕一区二区三区 | 国产精品视频免费一区| 久久成人国产| 久久躁狠狠躁夜夜爽| 久久精品99久久香蕉国产色戒| 亚洲天堂av在线免费| 免播放器亚洲一区| 中文在线不卡| 在线国产亚洲欧美| 好看的日韩视频| 亚洲电影下载| 亚洲午夜激情网页| 欧美在线关看| 亚洲第一网站| 蜜臀久久久99精品久久久久久| 美女精品自拍一二三四| 男人插女人欧美| 欧美激情国产高清| 亚洲色无码播放| 欧美wwwwww| 国产精品亚洲а∨天堂免在线| 国产日本欧美视频| 亚洲欧洲日产国码二区| 亚洲视频综合| 老鸭窝亚洲一区二区三区| 国产精品视频免费观看www| 午夜精品国产精品大乳美女| 久久国产日本精品| 亚洲欧美日韩精品一区二区| 亚洲一区二区在线视频| 久久精品毛片| 国产亚洲一区在线播放| 99在线精品免费视频九九视| 香蕉成人久久| 亚洲小说欧美另类社区| 久久久久久免费| 国产在线高清精品| 亚洲天堂av在线免费| 欧美顶级艳妇交换群宴| 久久国产精品99精品国产| 国产精品久久久久久久久久尿 | 99成人免费视频| 亚洲在线网站| 国产精品电影网站| 午夜精品久久久久久久男人的天堂| 欧美成年人视频网站| 欧美国产高潮xxxx1819| 国产一区二区三区不卡在线观看 | 免费h精品视频在线播放| 欧美一区二区精品| 在线看国产一区| 牛人盗摄一区二区三区视频| 久久se精品一区精品二区| 国内精品视频在线播放| 老司机免费视频久久| 久久精品免费| 久久综合激情| 亚洲精美视频| 亚洲国产日韩在线| 欧美国产激情| 欧美一区二区视频97| 亚洲免费在线电影| 国产一区二区精品久久91| 久久免费视频一区| 久久天天躁狠狠躁夜夜爽蜜月| 曰本成人黄色| 日韩午夜激情| 亚洲精品国产系列| 中文高清一区| 亚洲少妇自拍| 免费观看成人鲁鲁鲁鲁鲁视频| 中国av一区| 欧美激情精品久久久久久免费印度| 亚洲视频在线一区观看| 麻豆久久久9性大片| 欧美电影电视剧在线观看| 国产精品一区2区| 欧美激情精品久久久| 国产亚洲精品久久飘花| 亚洲精品日韩在线观看| 久久精品官网| 老巨人导航500精品| 国产欧美日韩亚州综合| av成人老司机| 欧美在线free| 国产区精品视频| 一区二区免费看| 亚洲一区精品视频| 国产免费一区二区三区香蕉精| 最近看过的日韩成人| 国产精品久久久久久久久免费樱桃| 欧美成人一区二区| 香蕉久久夜色| 欧美一区亚洲一区| 亚洲午夜免费视频| 欧美a级一区| 一区二区高清视频在线观看| 亚洲高清自拍| 欧美久久久久免费| 国产精品99久久久久久www| 亚洲精品久久久久久久久久久久| 久久久久久久久久久一区| 亚洲伊人色欲综合网| 国产欧美亚洲日本| 亚洲第一天堂av| 久久久99精品免费观看不卡| 韩国一区电影| 欧美日韩国产综合网| 久久成人免费电影| 日韩一区二区精品| 欧美丰满高潮xxxx喷水动漫| 亚洲永久在线| 一道本一区二区| 影音先锋日韩有码| 国产精品美女久久久免费| 香蕉久久夜色精品国产| 久久综合久久88| 亚洲一区二区在线免费观看视频| 国产欧美一区二区精品婷婷| 乱码第一页成人| 欧美一区二区免费视频| 国产女人水真多18毛片18精品视频| 美女国内精品自产拍在线播放| 亚洲性xxxx| 艳妇臀荡乳欲伦亚洲一区| 在线播放日韩欧美| 狠狠色综合播放一区二区 | 亚洲亚洲精品在线观看| 性欧美18~19sex高清播放| 99亚洲一区二区| 亚洲成色最大综合在线| 亚洲高清网站| 亚洲精品中文字幕女同| 久久一本综合频道| 亚洲乱码国产乱码精品精98午夜 | 国内激情久久| 在线观看不卡av| 亚洲美女黄色片| 亚洲午夜一区二区三区| 亚洲男人av电影| 亚洲一区二区在线播放| 久久国产精品99久久久久久老狼| 久久精品99久久香蕉国产色戒| 久久久国产精品亚洲一区| 另类酷文…触手系列精品集v1小说| 免费视频一区| 在线亚洲精品福利网址导航| 欧美日韩一区二区在线观看| 亚洲国产精品va在线看黑人动漫| 欧美激情一区二区久久久| 亚洲毛片在线| 美国三级日本三级久久99| 欧美日韩你懂的| 亚洲国产精品悠悠久久琪琪| 午夜精品久久久久99热蜜桃导演| 久久夜色精品国产| 亚洲欧美三级在线| 欧美高清在线精品一区| 国产午夜精品一区二区三区视频| 国产一区二区三区免费不卡| 99精品热视频| 国产精品推荐精品| 免费看的黄色欧美网站| 欧美色另类天堂2015| 欧美成人精品h版在线观看| 国产欧美一区二区三区视频| 一本久道综合久久精品| 亚洲深夜福利| 国产精品视频99| 亚洲深夜影院| 一区二区欧美在线观看| 一区二区三区精品国产| 欧美日韩大片| 亚洲视频精选| 欧美在线地址| 激情五月***国产精品| 欧美专区亚洲专区| 久久综合中文色婷婷| 亚洲第一精品电影| 欧美日韩国产专区| 午夜精品久久久久久久久久久久 | 久久久久九九九| 久久人体大胆视频| 亚洲韩国青草视频| 国产精品福利影院| 久久午夜精品一区二区| 日韩小视频在线观看| 久久er精品视频| 在线视频欧美日韩| 欧美国产一区二区| 欧美国产精品一区| 午夜欧美精品| 一区二区三区日韩精品视频| 另类图片综合电影| 亚洲在线视频一区| 亚洲国产影院| 精品电影在线观看| 黄色另类av|