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 }
心得: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 }
心得: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维情况下