程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 2057 The lost house

POJ 2057 The lost house

編輯:C++入門知識

這道題求的是期望。

首先,一看到期望,就會想到可以將問題分成若干個子問題,再分開算期望,所以這道題可以使用動態規劃。

注意到每個葉子有房子的概率是均等的。所以答案就是遍歷每個葉子最少的步數/葉子的總數。

所以問題劃歸為求遍歷所有葉子的最少步數。

我們令fail[x]為以x為根的子樹找不到房子的最少步數。

su[x]為以x為根的子樹中找到房子最少步數。

le[x]為以x為根的子樹中葉子的個數。

則有 fail[x]=sigma(fail[y]+2);(worm[x]=false) fail[x]=0 (worm[x]=true);

su[x]+=(fail[x]+1)*le[y]+su[y];(其中fail[x]為在y之前沒有找到房子的步數)

顯然,su[x]和x兒子的順序是有很大關系的。

第一種想法是枚舉所有的全排列。雖然每個節點只有最多8個兒子,但8!=40320,太大。

第二種想法是貪心。我們可以使用調整的思想來確定兒子的順序。

設y1,y2為x的兩個相鄰的兒子。若y1在y2之前,則ans1=(fail[x]+1)*le[y1]+su[y1]+(fail[x]+2+fail[y1]+1)*le[y2]+su[y2]

若交換y1,y2,則有ans2=(fail[x]+1)*le[y2]+su[y2]+(fail[x]+2+fail[y2]+1)*le[y1]+su[y1]

則ans1-ans2=(fail[y1]+2)*le[y2]-(fail[y2]+2)-le[y1]。

所以可以根據這個排序。然後計算。

【總結】

求期望的題要注意搞清究竟要求什麼,不要盲目上手,要想方設法的將問題化繁為簡。像上述做法,整個過程中不涉及任何浮點運算,十分優秀。

【代碼】


[cpp] 
#include <iostream> 
#include <cstring> 
#include <string> 
#include <cstdio> 
#include <algorithm> 
#include <vector> 
using namespace std; 
 
const int N=1005; 
 
int su[N],fail[N],le[N],n,root; 
bool w[N]; 
vector<int> a[N]; 
 
bool cmp(int x,int y) 

    return (fail[x]+2)*le[y]<(fail[y]+2)*le[x]; 

 
void dp(int x) 

    int i,y; 
    if (a[x].empty()) 
    { 
        le[x]=1; 
        return; 
    } 
    for (i=0;i<a[x].size();i++) 
    { 
        y=a[x][i]; 
        dp(y); 
        le[x]+=le[y]; 
    } 
    sort(a[x].begin(),a[x].end(),cmp); 
    for (i=0;i<a[x].size();i++) 
    { 
        y=a[x][i]; 
        su[x]+=(fail[x]+1)*le[y]+su[y]; 
        fail[x]+=fail[y]+2; 
    } 
    if (w[x]) fail[x]=0; 

 
int main() 

    int i,j; 
    char ch; 
 
    freopen("in","r",stdin); 
    while (1) 
    { 
        scanf("%d",&n); 
        if (n==0) break; 
        memset(fail,0,sizeof(fail)); 
        memset(su,0,sizeof(su)); 
        memset(le,0,sizeof(le)); 
        memset(w,0,sizeof(w)); 
        for (i=1;i<=n;i++) 
            a[i].clear(); 
        for (i=1;i<=n;i++) 
        { 
            scanf("%d %c",&j,&ch); 
            if (j==-1) root=i; 
            else a[j].push_back(i); 
            w[i]=(ch=='Y'?true:false); 
        } 
        dp(root); 
        printf("%.4f\n",1.0*su[root]/le[root]); 
    } 

 


作者:ascii991

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved