hdu--4336--概率dp

其实 概率dp最后得到的期望 你是 顺序递推 还是 逆序递推 就是取决于你对于 dp[x]这个数组是如何去定义的

这边 逆序递推的 思想 可以去看下

    传送   感觉这篇博客下方的评论 讲得还可以

至于顺序递推的 可以参照下 porker给我的这个公式 

dp[x]就是表示 抽完x这个状态下所有的卡片 所需要的次数 - 所以初始化就可以定义 dp[0] = 0 了

你可以看到 当期望存在线性的递推关系的时候 我们不是按照 signma( p[i] * x[i] )来计算E(i)下的期望 而是通过 期望的状态转移来进行计算

就是说 通过算出 E(a) - > E (b)  满足该情况的p[a->b]来完成  就是上一状态通过概率为p[a->b]来实现对于目前状态的转移  当然也有一定概率p[b->b]就是还是保持原状态

我先放 逆序的代码  后面的就是顺序的代码

 1 #include <iostream>
 2 #include <iomanip>
 3 using namespace std;
 4 
 5 int n;
 6 const int size = 25;
 7 double p[size];
 8 double dp[1<<size];
 9 
10 void solve( )
11 {
12     double sum , sumP;
13     for( int i = (1<<n)-2 ; i>=0 ; i-- )
14     {
15         sum = sumP = 0;
16         for( int j = 0 ; j<n ; j++ )
17         {
18             if( ( i & (1<<j) )  )
19             {
20                 continue;
21             }
22             sum += p[j] * dp[ i ^ (1<<j) ];
23             sumP += p[j];
24         }
25         dp[i] = ( sum + 1.0 ) / sumP;
26     }
27 }
28 
29 int main()
30 {
31     cin.sync_with_stdio(false);
32     while( cin >> n )
33     {
34         for( int i = 0 ; i<n ; i++ )
35         {
36             cin >> p[i];
37         }
38         dp[(1<<n)-1] = 0;
39         solve( );
40         cout << setiosflags(ios::fixed);
41         cout << setprecision(5) << dp[0] << endl;
42     }
43     return 0;
44 }
View Code

 

 1 #include <iostream>
 2 #include <iomanip>
 3 using namespace std;
 4 
 5 int n;
 6 const int size = 25;
 7 double p[size];
 8 double dp[1<<size];
 9 
10 void solve( )
11 {
12     double sum , sumP;
13     for( int i = 1 ; i<=(1<<n)-1 ; i++ )
14     {
15         sum = sumP = 0;
16         for( int j = 0 ; j<n ; j++ )
17         {
18             if( ( i & (1<<j) ) == 0 )
19             {
20                 continue;
21             }
22             sum += p[j] * dp[ i ^ (1<<j) ];
23             sumP += p[j];
24         }
25         dp[i] = ( sum + 1.0 ) / sumP;
26     }
27 }
28 
29 int main()
30 {
31     cin.sync_with_stdio(false);
32     while( cin >> n )
33     {
34         for( int i = 0 ; i<n ; i++ )
35         {
36             cin >> p[i];
37         }
38         dp[0] = 0;
39         solve( );
40         cout << setiosflags(ios::fixed);
41         cout << setprecision(5) << dp[(1<<n)-1] << endl;
42     }
43     return 0;
44 }
View Code

他们实在很相似 就是定义与转移的区别 想起来 真的狠头痛 ..;

 

这边 在放一个XX论文的题目 但他那边没给出状态转移 我这边也写下

„„在2003年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字。只要凑齐所有百事球星的名字,就可以参加百事世界杯之旅的抽奖活动,获取球星背包、随身听,更可以赴日韩观看世界杯。还不赶快行动!„„” 你关上电视,心想:假设有n个不同球星的名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢?

 

dp[0] = 0

dp[x] = (n-x)/n*dp[x] + x/n*dp[x-1]+1

dp[x] = dp[x-1]+n/x;

dp(0)=0
dp(1)=dp(0)+n/1
dp(2)=dp(1)+n/2
.....
dp(n)=dp(n-1)+n/n

可以得到dp[n] = n * (1/1+1/2+1/3+...1/n)

或者

dp[n]=0

dp[x] = x/n*dp[x]+(n-x)/n*dp[x+1]+1

dp[x] = dp[x+1]+n/(n-x)



 

 

posted @ 2014-11-27 13:18  radical  阅读(190)  评论(0编辑  收藏  举报