【DP_概率DP专辑】【10、4最新更新】【from zeroclock's blog】

    进入大学之后发现自己对概率问题很不感冒,其实一直都是这样,高中就没好好读数学。概率不好的结果就是对概率类dp掌握得just so so,因为对这类dp的状态和转移不敏感,要么是yy,要么是花很长时间想状态想转移。

    现在痛下决心,好好虐待自己一段时间,做下概率dp。


    Codeforces 148D Bag of mice  

   状态转移方程比较难想,开虚拟比赛的时候花了50分钟硬是没AC.设win[i][j]表示公主赢的概率,lost[i][j]表示龙输的概率,然后根据题意进行转移。状态转移方程如下:

    win[i][j] = i * 1.0 / (i + j);                                                            //i只白老鼠j只黑老鼠时公主选白老鼠            
    win[i][j] += lost[i][j-1] * j * 1.0 / (i + j);                                       //i只白老鼠j只黑老鼠时公主选黑老鼠,但公主选完黑老鼠后龙还是输了      
    lost[i][j]  = j * 1.0 / (i + j) * win[i-1][j-1] * (i * 1.0 / (i + j - 1));    //i只白老鼠j只黑老鼠时龙选黑老鼠,选完后跳出去只白老鼠    
    lost[i][j] += j * 1.0 / (i + j) * win[i][j-2] * ((j - 1) * 1.0 / (i + j - 1));  //i只白老鼠j只黑老鼠时龙选黑老鼠,选完后跳出去只黑老鼠    

     

     Sgu 495 Kids and Prizes  

    比较简单的概率DP。m个人选n个礼物,问选中的期望。因为每个人选择礼物是独立,那么猜想求解过程n只是用来求概率。设dp[i]表示第i个人选中礼物的概率,np[i]表示第i个人不选中礼物的概率。那么dp[i] = dp[i-1] * np[i-1] + dp[i-1] * (dp[i-1]-1.0/n),表示:如果上一个人没选中,那么本次选中的概率和上次选中的概率一样是dp[i-1],如果上次已经选中,那么本次选中的概率是dp[i-1]-1.0/n。而np[i] = 1- dp[i];这种方法复杂度是O(m),其实O(1)就可以了。从反方向求不被选中的期望,那么答案就是n-n*((n-1)/n)^m,每个礼物不被m个人选中的概率是((n-1)/n)^m,因为每个礼物都一样,所以直接乘n就Ok。


     Zoj 3383 Patchouli's Spell Cards

     概率DP,选m个位置填充,每个填充的数的范围是1..n,问至少有l个数相同的概率。从反面来考虑,求不出现l个相同数的概率p,1-p既是答案。模型转换后就可以进行DP了,设dp[i][j]表示选到第i个数填充了j个位置的方案数,那么dp[i][j] = dp[i-1][j-k] + C[m-(j-k)][k](k < l && k <=j),,然后求出所有方案书total,ans = (total - dp[n][m]) / total.这种方法复杂度是O(n*m*l),其实有种复杂度为O(min(n,m)*min(n,m)*l),dp[i][j]表示选了i个数填充j个位置的方案数,这里的i不必是1...i,只要是i个不同的数即可,这样和n就没多大关系,转移方程类似。数很大要用大数。    


     Zoj 3460 Help Me Escape 

    浙大月赛的题目,比赛的时候想到了做法,但是被一题字符串卡住,没来得及敲。题目的大概意思是一只吸血鬼每次随机的选择n个洞中的任意一个,如果该吸血鬼的攻击值大于该洞ci那么直接可以花费Ti的时间就可以出去,不然要奋斗一天该吸血鬼攻击值增加ci再 随机选择n个洞.口设dp[i]表示攻击力为i时逃跑的期望,那么状态转移方程就为dp[i] = sum(wi) / n,当ci < i时,wi = (1+sqrt(5))/ 2 * ci * ci,当ci >=i时wi = 1 + dp[i+ci]。可以逆序进行状态转移也可以用记忆化搜索,记忆化搜索更容易理解。


     Hdu 4405 Aeroplane chess 

    从位置0开始,每步随机走1,2,3,4,5,6个位置,问走到大等于n位置的期望步数,还有一些位置带有限制,某些xi对应着yi,表示到xi就必须马上走到yi,不算一步。和上题很像,更简单些,

     简单点好想点的做法是设dp[i]表示到i时的期望,p[i]表示到i时的概率,那么dp[i] += (dp[j] + p[j]) * 1 / 6.0,p[i] += p[j] * 1 / 6.0,(从j走到i) 当next[i] != i时dp[i] = dp[j],p[i] = p[j];最后的答案是dp[n];这个公式是这样推导来的,假设dp[j] = day * p,那么dp[i] = (day + 1) *p* 1 / 6.0,即dp[i] = (dp[j] + p[j]) * 1 / 6.0.

    化解后,dp[i]表示到达i位置的期望天数.dp[i] = dp[j] (next[i] == i), dp[i] += (dp[j] + 1) * 1 / 6.0。


     Hdu 4336 Card Collector 

    状态压缩DP解之,dp[i]表示i这个状态到最终状态需要的期望卡片数,dp[i] =dp[i] * myself + sum( dp[j] * p[k] = sum( dp[j] * p[k]) / (1-myself)(i|k=j且i!=j,myself表示保持原状的概率).

    这道题其实是我YY用容斥原理过的,看测试数据很像可以2^n枚举,然后把把枚举到的卡片概率加起来算期望,奇数加偶数减,然后就过了。想不清楚为什么可以用容斥原理,然后就找了个挺靠谱的解释自我安慰,E1表示买买到1的期望,E1 = 1/p1,也就是说E1包里面肯定包含1这张卡片,当我们计算E1和E2时,是不是会有一种情况:我们想要卡片1的时候已经买到了卡片2,然后我们又要计算买卡片2的期望,正是因为这样的交集使得我们可以用容斥,交集的期望E12 = 1 / (p1 +p2) 表示肯定买到1、2中的其中一包,E123就表示肯定买到1、2、3中的某一种,我们在计算E12,E13,E23的时候E123多减了一次,要加回来,以此类推....


148D代码

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #define MAX 1100  
  4.   
  5.   
  6. double ans;  
  7. double win[MAX][MAX],lost[MAX][MAX];  
  8.   
  9.   
  10. int main()  
  11. {  
  12.     int i,j,n,m;  
  13.       
  14.       
  15.     while (scanf("%d%d",&n,&m) != EOF) {  
  16.           
  17.         ans = 0;  
  18.         memset(win,0,sizeof(win));  
  19.         memset(lost,0,sizeof(lost));  
  20.           
  21.           
  22.         for (i = 1; i <= n; ++i)  
  23.             win[i][0] = 1.0;  
  24.         for (i = 1; i <= n; ++i)  
  25.             for (j = 1; j <= m; ++j) {  
  26.                   
  27.                 win[i][j] = i * 1.0 / (i + j) + lost[i][j-1] * j * 1.0 / (i + j);  
  28.                 lost[i][j]  = j * 1.0 / (i + j) * win[i-1][j-1] * (i * 1.0 / (i + j - 1));  
  29.                 lost[i][j] += j * 1.0 / (i + j) * win[i][j-2] * ((j - 1) * 1.0 / (i + j - 1));  
  30.             }  
  31.   
  32.               
  33.             printf("%.9lf\n",win[n][m]);  
  34.     }  
  35. }  

SGU 495代码:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #define MAX 1100000  
  4.   
  5.   
  6. int n,m;  
  7. double ans,dp[MAX],np[MAX];  
  8.   
  9.   
  10. int main()  
  11. {  
  12.     int i,j,k;  
  13.   
  14.   
  15.     while (scanf("%d%d",&n,&m) != EOF) {  
  16.   
  17.         ans = 1;  
  18.         dp[1] = 1,dp[0] = 0;  
  19.         for (i = 2; i <= m; ++i) {  
  20.               
  21.             dp[i] = dp[i-1] * np[i-1] + dp[i-1] * (dp[i-1] - 1.0/n);  
  22.             np[i] = 1-dp[i];  
  23.             ans += dp[i];  
  24.         }  
  25.         printf("%.10lf\n",ans);  
  26.     }  
  27. }  


Zoj 3383 代码

[java]  view plain copy
  1. ///*O(min(n,m)*min(n,m)*l)  
  2. import java.math.BigInteger;  
  3. import java.util.Scanner;  
  4.   
  5. public class Zoj3380 {  
  6.   
  7.     static BigInteger[][] C = new BigInteger[110][110];  
  8.     static BigInteger[][] dp = new BigInteger[110][110];  
  9.       
  10.       
  11.     static void Initial() {  
  12.           
  13.         for (int i = 0; i < 110; ++i)  
  14.             C[i][0] = C[i][i] = BigInteger.ONE;  
  15.         for (int i = 2; i < 110; ++i)  
  16.             for (int j = 1;  j < i; ++j)  
  17.                 C[i][j] = C[i-1][j].add(C[i-1][j-1]);  
  18.     }  
  19.       
  20.     public static void main(String[] args) {  
  21.           
  22.         Initial();  
  23.         Scanner cin = new Scanner(System.in);  
  24.           
  25.           
  26.         while (cin.hasNext()) {  
  27.               
  28.             int m = cin.nextInt();  
  29.             int n = cin.nextInt();  
  30.             int l = cin.nextInt();  
  31.             if (l > m) {  
  32.                   
  33.                 System.out.println("mukyu~");  
  34.                 continue;  
  35.             }  
  36.               
  37.               
  38.             BigInteger total = BigInteger.valueOf(n).pow(m);  
  39.             if (l > m / 2) {  
  40.                   
  41.                 BigInteger ans = BigInteger.ZERO;  
  42.                 for (int i = l; i <= m; ++i)  
  43.                     ans = ans.add(C[m][i].multiply(BigInteger.valueOf(n-1).pow(m-i)));  
  44.                 ans = ans.multiply(BigInteger.valueOf(n));  
  45.                 BigInteger gcd = ans.gcd(total);  
  46.                 System.out.println(ans.divide(gcd)+"/"+total.divide(gcd));  
  47.             }  
  48.             else {  
  49.                   
  50.                 for (int i = 0;i <= m; ++i)  
  51.                     for (int j = 0; j <= m; ++j)  
  52.                         dp[i][j] = BigInteger.ZERO;  
  53.                 dp[0][0] = BigInteger.ONE;  
  54.                   
  55.                   
  56.                 for (int i = 1; i <= n && i <= m; ++i)  
  57.                     for (int j = 1; j <= m; ++j)  
  58.                         for (int k = 1; k < l && k <= j; ++k)  
  59.                             dp[i][j] = dp[i][j].add(dp[i-1][j-k].multiply(C[m-(j-k)][k]).multiply(BigInteger.valueOf(n-(i-1))));  
  60.                   
  61.                   
  62.                 BigInteger ans = BigInteger.ZERO;  
  63.                 BigInteger Jc = BigInteger.ONE;  
  64.                 for (int i = 1; i <= m; ++i) {  
  65.                   
  66.                     ans = ans.add(dp[i][m].divide(Jc));  
  67.                     Jc = Jc.multiply(BigInteger.valueOf(i+1));  
  68.                 }  
  69.   
  70.                   
  71.                 ans = total.subtract(ans);  
  72.                 BigInteger gcd = ans.gcd(total);  
  73.                 System.out.println(ans.divide(gcd)+"/"+total.divide(gcd));  
  74.             }  
  75.         }  
  76.     }  
  77. }//*/  
  78. /*O(m*m*l) 
  79. import java.math.BigInteger; 
  80. import java.util.Scanner; 
  81.  
  82. public class Zoj3380 { 
  83.  
  84.     static BigInteger[][] C = new BigInteger[110][110]; 
  85.     static BigInteger[][] dp = new BigInteger[110][110]; 
  86.      
  87.      
  88.     static void Initial() { 
  89.          
  90.         for (int i = 0; i < 110; ++i) 
  91.             C[i][0] = C[i][i] = BigInteger.ONE; 
  92.         for (int i = 2; i < 110; ++i) 
  93.             for (int j = 1;  j < i; ++j) 
  94.                 C[i][j] = C[i-1][j].add(C[i-1][j-1]); 
  95.     } 
  96.      
  97.     public static void main(String[] args) { 
  98.          
  99.         Initial(); 
  100.         Scanner cin = new Scanner(System.in); 
  101.          
  102.          
  103.         while (cin.hasNext()) { 
  104.              
  105.             int m = cin.nextInt(); 
  106.             int n = cin.nextInt(); 
  107.             int l = cin.nextInt(); 
  108.             if (l > m) { 
  109.                  
  110.                 System.out.println("mukyu~"); 
  111.                 continue; 
  112.             } 
  113.              
  114.              
  115.             BigInteger total = BigInteger.valueOf(n).pow(m); 
  116.             if (l > m / 2) { 
  117.                  
  118.                 BigInteger ans = BigInteger.ZERO; 
  119.                 for (int i = l; i <= m; ++i) 
  120.                     ans = ans.add(C[m][i].multiply(BigInteger.valueOf(n-1).pow(m-i))); 
  121.                 ans = ans.multiply(BigInteger.valueOf(n)); 
  122.                 BigInteger gcd = ans.gcd(total); 
  123.                 System.out.println(ans.divide(gcd)+"/"+total.divide(gcd)); 
  124.             } 
  125.             else { 
  126.                  
  127.                 for (int i = 0;i <= n; ++i) 
  128.                     for (int j = 0; j <= m; ++j) 
  129.                         dp[i][j] = BigInteger.ZERO; 
  130.                 dp[0][0] = BigInteger.ONE; 
  131.                  
  132.                  
  133.                 for (int i = 1; i <= n; ++i) 
  134.                     for (int j = 0; j <= m; ++j) 
  135.                         for (int k = 0; k < l && k <= j; ++k) 
  136.                             dp[i][j] = dp[i][j].add(dp[i-1][j-k].multiply(C[m-(j-k)][k])); 
  137.                 BigInteger ans = total.subtract(dp[n][m]); 
  138.                 BigInteger gcd = ans.gcd(total); 
  139.                 System.out.println(ans.divide(gcd)+"/"+total.divide(gcd)); 
  140.             } 
  141.         } 
  142.     } 
  143. } 
  144. 10 20 3 
  145. 176771177/800000000 
  146. */  


Zoj 3460 代码

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <math.h>  
  4. #include <algorithm>  
  5. using namespace std;  
  6. #define MAX 20000  
  7.   
  8.   
  9. double dp[MAX], ans;  
  10. int c[MAX], vis[MAX];  
  11. int n, m, cost[MAX];  
  12.   
  13.   
  14. void Solve_DP() {  
  15.   
  16.     memset(dp, 0, sizeof (dp));  
  17.     for (int i = 2 * c[n]; i >= m; --i) {  
  18.   
  19.         for (int j = 1; j <= n; ++j)  
  20.             if(i > c[j]) dp[i] += cost[j];  
  21.             else dp[i] += 1 + dp[c[j] + i];  
  22.         dp[i] /= n;  
  23.     }  
  24. }  
  25. double Calculate(int att) {  
  26.   
  27.     if (vis[att])  
  28.         return dp[att];  
  29.     vis[att] = 1;  
  30.   
  31.   
  32.     dp[att] = 0;  
  33.     for (int i = 1; i <= n; ++i)  
  34.         if (att > c[i])  
  35.              dp[att] += cost[i];  
  36.         else dp[att] += Calculate(att+c[i]) + 1;  
  37.   
  38.   
  39.     dp[att] /= n;  
  40.     return dp[att];  
  41. }  
  42.   
  43.   
  44. int main() {  
  45.     int i, j, k;  
  46.   
  47.   
  48.     while (scanf("%d%d", &n, &m) != EOF) {  
  49.   
  50.         for (i = 1; i <= n; ++i)  
  51.             scanf("%d", &c[i]);  
  52.         sort(c + 1, c + 1 + n);  
  53.         for (i = 1; i <= n; ++i)  
  54.             cost[i] = (1 + sqrt(5)) / 2 * c[i] * c[i];  
  55.   
  56.   
  57.         //Solve_DP();  
  58.         //printf("%.3lf\n", dp[m]);  
  59.         memset(vis,0,sizeof(vis));  
  60.         ans = Calculate(m);  
  61.         printf("%.3lf\n",ans);  
  62.     }  
  63. }  


Hdu 4405 代码

[cpp]  view plain copy
  1. #pragma comment(linker, "/STACK:1024000000,1024000000")  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include <vector>  
  5. #include <algorithm>  
  6. using namespace std;  
  7. #define MAX 100010  
  8.   
  9.   
  10. int n,m,next[MAX];  
  11. double dp[MAX];  
  12.   
  13.   
  14. double Solve_DP(int day) {  
  15.   
  16.     if (day >= n) return 0;  
  17.     if (dp[day]) return dp[day];  
  18.   
  19.   
  20.     if (next[day])   
  21.         dp[day] = Solve_DP(next[day]);  
  22.     else  {  
  23.   
  24.         for (int i = 1; i <= 6; ++i)  
  25.             dp[day] += (Solve_DP(day + i) + 1) * 1/6.0;  
  26.     }  
  27.     return dp[day];  
  28. }  
  29. double Solve_DP1() {  
  30.       
  31.     for (int i = n - 1; i >= 0; --i)  
  32.         if (next[i]) dp[i] = dp[next[i]];  
  33.         else  {  
  34.               
  35.             for (int j = 1; j <= 6; ++j) {  
  36.                   
  37.                 int k = i + j >= n ? n : i + j;  
  38.                 dp[i] += (dp[k] + 1) * 1.0 / 6.0;  
  39.             }  
  40.         }  
  41.           
  42.           
  43.     return dp[0];  
  44. }  
  45.   
  46.   
  47. int main()  
  48. {  
  49.     int i,j,k,a,b;  
  50.   
  51.   
  52.     while (scanf("%d%d",&n,&m),n + m) {  
  53.   
  54.         for (i = 0; i <= n; ++i)  
  55.             dp[i] = next[i] = 0;  
  56.         for (i = 1; i <= m; ++i)   
  57.             scanf("%d%d",&a,&b),next[a] = b;  
  58.   
  59.           
  60.         printf("%.4lf\n",Solve_DP1());  
  61.         //printf("%.4lf\n",Solve_DP(0));  
  62.     }  
  63. }  

你可能感兴趣的:(【DP_概率DP专辑】【10、4最新更新】【from zeroclock's blog】)