oj练习---dp专题

1.POJ 3744  Scout YYF I

经典的dp模型,但是要用到快速矩阵幂加速,分段的思想

 1 # include <stdio.h>
 2 # include <algorithm>
 3 # include <string.h>
 4 # include <iostream>
 5 using namespace std;
 6 
 7 int mines[15];
 8 
 9 void matrixMulti(double a[2][2], double b[2][2]){
10     double i,j,k,l;
11     i = a[0][0]*b[0][0]+a[0][1]*b[1][0];
12     j = a[0][0]*b[0][1]+a[0][1]*b[1][1];
13     k = a[1][0]*b[0][0]+a[1][1]*b[1][0];
14     l = a[1][0]*b[0][1]+a[1][1]*b[1][1];
15     a[0][0]=i,a[0][1]=j,a[1][0]=k,a[1][1]=l;
16 }
17 
18 double quickPow(const double p, int x){
19     if(x == -1){
20         return 1.0;
21     }
22     double a[2][2] = {0, 1, 1-p, p}, res[2][2] = {1,0,0,1};
23     while(x){
24         //printf("this 3\n");
25         if(x&1){
26             matrixMulti(res, a);
27         }
28         x/=2;
29         matrixMulti(a,a);
30     }
31     return res[0][1]*(1-p);
32 }
33 
34 int main(){
35     int num;
36     double p, result;
37     while(scanf("%d%lf",&num, &p) != EOF){
38         memset(mines, 0, sizeof(mines));
39         for(int i = 1 ; i <= num; ++i){
40             scanf("%d", mines + i);
41         }
42         if(mines[1] == 1){
43             printf("%.7f\n", 0.0);
44             continue;
45         }
46         mines[0] = 0;
47         result = 1.0;
48         sort(mines, mines+num+1);
49         for(int i = 1; i <= num; ++i){
50             result *= quickPow(p, mines[i] - mines[i - 1] - 1);
51         }
52         if(result < 0){
53             result = 0;
54         }
55         if(result > 1){
56             result =1;
57         }
58         printf("%.7f\n", result);
59     }
60     return 0;
61 }
View Code

心得:1.dp[i]=dp[i-2]*(1-p)+dp[i-1]*p,其实就是连续跟1-p/p相乘,自然想到矩阵加速。2.快速幂的思想,将O(n)降成O(lg(n))。

3.[0, 1; 1-p, p]  * [dp[i-2]; dp[i-1]] =  [dp[i-1]; dp[i]],然后变成幂运算之后就可以加速了。多次乘以相同的数值其实就是幂运算(一个数就是整数幂,多个数的式子就是矩阵幂)

2.POJ 2096 Collecting Bugs

经典的dp求期望的题,注意理解反向求期望的思想,以及C++整数除法跟数学上的除法的区别(他是下取整的)

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 #include <fstream>
 7 using namespace std;
 8 
 9 double dp[1010][1010];
10 int main()
11 {
12     int n, s;
13     double a, b, c, d;
14     //cout << sizeof(dp);
15     while(scanf("%d%d", &n, &s) != EOF){
16         memset(dp, 0, sizeof(dp));
17         for(int i = n; i >= 0; --i){
18             for(int j = s; j >= 0; --j){
19                 if(i==n&&j==s)continue;
20                 a = 1.0*(n-i)/n*j/s;
21                 b = 1.0*i/n*(s-j)/s;
22                 c = 1.0*i/n*j/s;
23                 d = 1.0*(n-i)/n*(s-j)/s;
24                 dp[i][j] = (a * dp[i+1][j]+b*dp[i][j+1]+d*dp[i+1][j+1] + 1.0)/(1.0-c);
25             }
26         }
27         printf("%.4f\n",dp[0][0]);
28     }
29     return 0;
30 }
View Code

心得:1.C++整数除法跟数学上的除法的区别(他是下取整的)2.反向求期望的思想跟期望的性质E(aA+bB+....) = aE(A)+bE(B)+.....3.本题的递推公式需要变形计算一下:dp[i][[j] = a*dp[i+1][j]+b*dp[i][j]+c*dp[i][j+1]+d*dp[i+1][j+1]+14.动态规划矩阵的边界条件的控制。容易变坑,尤其是2维情况下

posted @ 2018-10-10 21:13  回溯法  阅读(357)  评论(0编辑  收藏  举报