概率dp专场

 

专题链接

第一题--poj3744 Scout YYF I  链接 (简单题)

算是递推题 如果直接推的话 会TLE 会发现 在两个长距离陷阱中间 很长一部分都是重复的 我用 a表示到达i-2步的概率 b表示到达i-1步的概率 c表示到达i步的概率

如果数很大的话 中间肯定会有重复的a,b,c 直接将i挪到最近的陷阱前一位 i = a[o]-1,大大节省时间。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define LL long long
12 #define INF 0xfffffff
13 const double eps = 1e-8;
14 const double pi = acos(-1.0);
15 const double inf = ~0u>>2;
16 int x[12];
17 int main()
18 {
19     int i,n,j;
20     double p;
21     while(cin>>n)
22     {
23         cin>>p;
24         for(i = 0 ;i < n ;i++)
25         {
26             cin>>x[i];
27         }
28         sort(x,x+n);
29         double a = 1.0,b=0.0,c;
30         double ta = 0,tb = 0;
31         int o = 0;
32         if(x[0]==1)
33         a = 0;
34         else a = 1;
35         for(i = 2; i <= x[n-1]+1 ; i++)
36         {
37             if(i==x[o])
38             {
39                 o++;
40                 while(x[o]==x[o-1])
41                 o++;
42                 c = 0;
43             }
44             else
45             c = a*p+b*(1.0-p);
46             b = a;
47             a = c;
48             if(o<n&&fabs(ta-a)<eps&&fabs(tb-b)<eps)
49             i = x[o]-1;
50             ta = a;
51             tb = b;
52         }
53         printf("%.7f
",c);
54     }
55     return 0;
56 }
View Code

第二题--poj3071Football(简单题)

dp[i][j] 表示第i场j赢的概率 那么可以写出方程dp[i][j] += dp[i-1][g]*p[j][g]. 

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 100000
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double p[130][130];
18 double dp[130][130];
19 int pp[12];
20 int main()
21 {
22     int i,j,n,g;
23     pp[0] = 1;
24     for(i = 1 ;i <= 10 ;i++)
25     pp[i] = pp[i-1]*2;
26     while(cin>>n)
27     {
28         if(n==-1) break;
29         memset(dp,0.0,sizeof(dp));
30         int k = n;
31         n = pp[n];
32         for(i = 1; i <=n ; i++)
33             for(j = 1 ;j <= n; j++)
34             cin>>p[i][j];
35         for(i = 1; i <=n ;i++)
36         {
37             if(i%2)
38             dp[1][i] = p[i][i+1];
39             else
40             dp[1][i] = p[i][i-1];
41         }
42         for(i = 2 ;i <= k ;i++)
43         {
44             for(j = 1 ;j <= n ;j+=pp[i])
45             {
46                 for(g = j; g < j+pp[i-1] ; g++)
47                 {
48                     for(int e = j+pp[i-1] ; e < j+pp[i] ; e++)
49                     {
50                         dp[i][g]+=dp[i-1][g]*dp[i-1][e]*p[g][e];
51                         dp[i][e]+=dp[i-1][e]*dp[i-1][g]*p[e][g];
52                     }
53                 }
54             }
55         }
56         double maxz = 0;
57         int ans;
58         for(i = 1; i <= n ;i++)
59         {
60             if(maxz<dp[k][i])
61             {
62                 maxz = dp[k][i];
63                 ans = i;
64             }
65             //printf("%.5lf %d
",dp[k][i],i);
66         }
67         cout<<ans<<endl;
68     }
69     return 0;
70 }
View Code

第三题--CodeForces 148D(简单题)

刚开始看错了题意,以为一次跳出一个老鼠,按概率直接算,WA后发现dragon画的时候会另有一只跳出来,这样就根据跳出来的是黑还是白分两种情况计算。

如果当前是dragon轮 也就是(总数-剩余数)%3!=0 时  dp[i][j] = j/(i+j)*((j-1)/(i+j-1)*dp[i][j-2]+i/(i+j-1)*dp[i-1][j-1])

dp[i][j] 表示还有i只白老鼠及j只黑老鼠时princess赢的概率。 princess轮计算方式类似。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N][N];
18 int main()
19 {
20     int i,a,b,j;
21     while(cin>>a>>b)
22     {
23         memset(dp,0,sizeof(dp));
24         for(i = 1 ;i <= a ; i++)
25         {
26             if((a+b-i)%3==0)
27             dp[i][0] = 1;
28         }
29         for(i = 1 ; i <= a ;i++)
30             for(j = 1 ;j <= b ;j++)
31             {
32                 if((a+b-(i+j))%3)
33                 {
34                     if(j>=2)
35                     dp[i][j] = j*1.0/(i+j)*((j-1)*1.0/(i+j-1)*dp[i][j-2]+(i*1.0)/(i+j-1)*dp[i-1][j-1]);
36                     else
37                     dp[i][j] = j*1.0/(i+j)*dp[i-1][j-1];
38                 }
39                 else
40                 {
41                     dp[i][j] = i*1.0/(i+j)+j*1.0/(i+j)*dp[i][j-1];
42                 }
43                 //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
44             }
45         printf("%.9lf
",dp[a][b]);
46     }
47     return 0;
48 }
View Code

 第四题--POJ 2151 Check the difficulty of problems 

这个题正推不好推,可以求逆,dp[i][j][g]表示第i个队在前g个题里解决了j道题的概率 再令开一dd[i][j]累加和保存第i队最多解决了j道题的概率

这样依次求出每队解决大于1道题的概率减掉每队解决少于n道的概率 即为每队至少解决一道并且冠军队解决至少n道的概率

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-12;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N][45][45],dd[N][45];
18 double p[N][45];
19 int main()
20 {
21     int i,j,n,m,t,g,e;
22     while(cin>>m>>t>>n)
23     {
24         if(!n||!m||!t) break;
25         memset(dp,0.0,sizeof(dp));
26         memset(dd,0.0,sizeof(dd));
27         for(i = 1; i <= t ; i++)
28         {
29             dp[i][0][0] = 1.0;
30             for(j = 1; j <= m ;j++)
31             {
32                 cin>>p[i][j];
33                 dp[i][0][j] = (1.0-p[i][j])*dp[i][0][j-1];
34             }
35             dd[i][0] = dp[i][j][m];
36         }
37         for(i = 1 ;i <= t ;i++)
38             for(j = 1 ;j <= m ;j++)
39             {
40                 e = 1 ;
41                 for(g = j ;g <= m ; g++)
42                 {
43                     dp[i][j][g] = dp[i][j-1][g-1]*p[i][g]+dp[i][j][g-1]*(1-p[i][g]);
44                 }
45                 dd[i][j] = dd[i][j-1]+dp[i][j][m];
46             }
47         double ans = 1.0,ss=1.0;
48         for(i = 1; i <= t; i++)
49         {
50             ans*=dd[i][m]-dd[i][0];
51             ss*=dd[i][n-1]-dd[i][0];
52         }
53         printf("%.3f
",ans-ss);
54     }
55     return 0;
56 }
View Code

第五题--POJ 2096 Collecting Bugs (简单期望题)

学习完这题可以了解到这一类期望题的解法,确定好一个边界状态,可能是初态也可能是终态,然后向后或向前推。

这题可以确定的为终态,dp[n][s] = 0. 然后倒推就可以了 dp[i][j] = dp[i][j+1]*(s-j)*1.0/s*i/n+dp[i+1][j]*(n-i)/n*j/s+dp[i+1][j+1]*(n-i)/n*(s-j)/s+1+i*j*1.0/n/s;

一个方程一个未知数,dp[0][0]即为答案。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N][N];
18 int main()
19 {
20     int n,s,i,j;
21     while(cin>>n>>s)
22     {
23         memset(dp,0.0,sizeof(dp));
24         for(i = n ; i >= 0 ;i--)
25             for(j = s ; j >= 0 ;j--)
26             {
27                 if(i==n&&j==s) continue;
28                 dp[i][j] = dp[i][j+1]*(s-j)*1.0/s*i/n+dp[i+1][j]*(n-i)/n*j/s+
29                 dp[i+1][j+1]*(n-i)/n*(s-j)/s+1;
30                 dp[i][j] = dp[i][j]/(1-(i*j*1.0/n/s));
31 
32             }
33         printf("%.4f
",dp[0][0]);
34     }
35     return 0;
36 }
View Code

第六题--HDU 3853 LOOPS(简单期望题)

与上一题类似,可以确定终态 dp[r][c] = 0.然后根据可走的概率进行倒推,注意可能会有无解的情况,p[i][j][0]=1就会进入死循环。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N][N];
18 double p[N][N][3];
19 int main()
20 {
21 
22     int i,j,r,c;
23     while(cin>>r>>c)
24     {
25         memset(dp,0.0,sizeof(dp));
26         for(i = 1; i <= r ; i++)
27         {
28             for(j = 1; j <= c; j++)
29             {
30                 for(int g = 0 ; g < 3 ; g++)
31                 scanf("%lf",&p[i][j][g]);
32             }
33         }
34         for(i = r ; i >= 1 ; i--)
35         {
36             for(j = c ; j >= 1 ; j--)
37             {
38                 if(i==r&&j==c) continue;
39                 dp[i][j] = dp[i+1][j]*p[i][j][2]+dp[i][j+1]*p[i][j][1]+2;
40                 if(fabs(1-p[i][j][0])<eps) continue;
41                 dp[i][j] = dp[i][j]/(1-p[i][j][0]);
42             }
43         }
44         printf("%.3lf
",dp[1][1]);
45     }
46     return 0;
47 }
View Code

第七题--HDU 4405 Aeroplane chess (简单期望题)

投掷骰子的问题,也是一样的问题,确定终态求dp[0]。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 101000
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 int f[N];
18 double dp[N];
19 int main()
20 {
21     int n,m,i,j;
22     while(cin>>n>>m)
23     {
24         if(!n&&!m) break;
25         memset(f,0,sizeof(f));
26         memset(dp,0,sizeof(dp));
27         int x,y;
28         for(i = 1 ;i <=m ; i++ )
29         {
30             cin>>x>>y;
31             f[x] = y;
32         }
33         for(i = n-1 ; i >= 0 ; i--)
34         {
35             if(f[i])
36             dp[i] += dp[f[i]];
37             else
38             {
39                 for(j = 1 ;j <= 6; j++)
40                 dp[i] += dp[i+j]*1.0/6;
41                 dp[i]+=1;
42             }
43         }
44         printf("%.4f
",dp[0]);
45     }
46     return 0;
47 }
View Code

第八题--ZOJ 3640 Help Me Escape (简单期望题)

这个题是d的战斗力值  也就是当战斗力为多少的时候可以确定一个终态 ,很显然当值为maxz+1 的时候 它最大可达2*maxz.

这样就可以写出递推方程 dp[i] = (dp[i+c[j]]+1)*1/n;(第j出口所需战斗力》=i) dp[i] += day[j] (第j出口所需战斗力<i)

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 20010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 int c[105];
18 double dp[N];
19 int main()
20 {
21     int n,f,i,j;
22     while(cin>>n>>f)
23     {
24         memset(dp,0,sizeof(dp));
25         for(i = 0; i < n ;i++)
26         cin>>c[i];
27         sort(c,c+n);
28         for(i = 2*c[n-1] ; i >= f ; i--)
29         {
30             int o = 0,k=0;
31             double t = 0,tt=0;
32             for(j = 0 ; j < n ;j++)
33             {
34                 if(i>c[j])
35                 {
36                     int d = (1.0+sqrt(5.0))/2*c[j]*c[j];
37                     t+=1.0/n*d;
38                 }
39                 else
40                 {
41                     k++;
42                     if(c[j]==0) o++;
43                     else
44                     t+=1.0/n*(dp[i+c[j]]+1);
45                 }
46             }
47             if(o&&fabs(1-o*1.0/n)>eps)
48             dp[i] += (t+1)/(1-o*1.0/n);
49             dp[i] += t;
50         }
51         printf("%.3f
",dp[f]);
52     }
53     return 0;
54 }
View Code

H第九题--DU 4336 Card Collector(简单期望题)

 状压一下,然后确定终态倒推。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 20010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[1<<20],p[21];
18 int main()
19 {
20     int n,i,j,g;
21     while(scanf("%d",&n)!=EOF)
22     {
23         memset(dp,0,sizeof(dp));
24         for(i = 0 ;i < n; i++)
25         scanf("%lf",&p[i]);
26         for(j = (1<<n)-1 ; j>=0 ; j--)
27         {
28             double t = 0;
29             double o = 0;
30             for(g = 0; g < n ;g++)
31             if((1<<g)&j) continue;
32             else
33             {
34                 o+=p[g];
35                 t+=p[g]*dp[j+(1<<g)];
36             }
37             if(fabs(o)>eps)
38             dp[j] = (t+1)/o;
39         }
40         printf("%f
",dp[0]);
41     }
42     return 0;
43 }
View Code

第十题--SGU 495 Kids and Prizes(简单期望题)

正推题,这个题比较巧妙,可以确定初始态dp[1] = 1,因为第一个人拿到球的概率就为1,那么第i个拿到球的期望就为,他拿到球的概率*(dp[i-1]+1),他拿到球的概率就等于有球的房间/总房间

那么有球的房间就为n-dp[i-1],因为期望就为球数,所以dp[i-1]就为拿走的球数。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 100010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N];
18 int main()
19 {
20     int i,n,m;
21     while(cin>>n>>m)
22     {
23         memset(dp,0,sizeof(dp));
24         dp[1] = 1;
25         for(i = 2; i <= m ;i++)
26         dp[i] = (dp[i-1]+1)*(1-dp[i-1]/n)+dp[i-1]*dp[i-1]/n;
27         printf("%.10f
",dp[m]);
28     }
29     return 0;
30 }
View Code

第十一题--ZOJ 3329 One Person Game(简单期望题)

也是比较好推的题目,相对前面来说会多一个未知数,但是推到最后就会发现只有一个未知数,一个方程一个未知数,可以求解。

可以把每一步的期望分为2部分保存,可以准确算出的用dp[i]表示 依旧是未知的用o[i]保存他的系数,留到最后求解。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N],p[N],o[N];
18 int main()
19 {
20     int i,j,n,k1,k2,k3,g,a,b,c,t;
21     cin>>t;
22     while(t--)
23     {
24         memset(dp,0,sizeof(dp));
25         memset(p,0,sizeof(p));
26         memset(o,0,sizeof(o));
27         cin>>n>>k1>>k2>>k3>>a>>b>>c;
28         int k = k1+k2+k3;
29         for(i = 1; i <= k1 ; i++)
30             for(j = 1;j <= k2 ; j++)
31                 for(g = 1; g <= k3 ; g++)
32                 {
33                     if(i==a&&j==b&&g==c) continue;
34                     p[i+j+g]+=1.0/(k1*k2*k3);
35                 }
36         for(i = n ; i >= 0 ; i--)
37         {
38             for(j = 3; j <= k ; j++)
39             {
40                 dp[i]+=dp[i+j]*p[j];
41                 o[i]+=p[j]*o[i+j];
42             }
43             dp[i]+=1;
44             o[i]+=1.0/(k1*k2*k3);
45         }
46         if(fabs(1-o[0])>eps)
47         dp[0] = dp[0]/(1-o[0]);
48         printf("%.14f
",dp[0]);
49     }
50     return 0;
51 }
View Code

第十二题--HDU 4652 Dice

有两种询问,一种一个推法,n个相同的话,dp[i]表示最后有连续i个相同的到最后有n个相同的点数的期望,dp[i] = 0,dp[i] = 1.0/m*dp[i+1]+1+(m-1)/m*dp[1];

另开一数组保存dp[1] 的系数,最后求解。

n个两辆不同,与之类似 dp[i] = ((m-i)*1.0/m*dp[i+1]+1)+1.0/m*dp[1]+1.0/m*dp[2]+....+1.0/m*dp[i]; 化简一下,每次可以消掉一个未知数,求到dp[1]的时候自然只剩了一个未知数。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 1000010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N],o[N];
18 int main()
19 {
20     int i,t,n,m,k;
21     while(cin>>t)
22     {
23         while(t--)
24         {
25             memset(dp,0,sizeof(dp));
26             memset(o,0,sizeof(o));
27             scanf("%d%d%d",&k,&m,&n);
28             if(k==0)
29             {
30                 for(i = n-1 ; i >= 1 ; i--)
31                 {
32                     dp[i] = 1.0/m*dp[i+1]+1;
33                     o[i] = 1.0/m*o[i+1]+(m-1)*1.0/m;
34                 }
35                 dp[1] = dp[1]/(1-o[1]);
36                 dp[0] = dp[1]+1;
37                 printf("%.12f
",dp[0]);
38             }
39             else
40             {
41                 for(i = n-1 ;i >= 1 ; i--)
42                 {
43                     dp[i] = ((m-i)*1.0/m*dp[i+1]+1)/(1-(m-i)*1.0/m*o[i+1]-1.0/m);
44                     o[i] = ((m-i)*1.0/m*o[i+1]+1.0/m)/(1-(m-i)*1.0/m*o[i+1]-1.0/m);
45                 }
46                 dp[0] = dp[1]+1;
47                 printf("%.12f
",dp[0]);
48             }
49         }
50     }
51     return 0;
52 }
View Code

第十三题--HDU 4035 Maze(中等期望题)

树上求期望的题,其实也与之类似,仔细想下会发现叶子节点的期望状态比较好确定,因为它只有一个父亲节点所以这样写出来的方程会只有2个未知数,一个是父亲节点一个是1号节点,到最后父亲节点肯定只有1,所以又会变成一个方程一个未知数。

dp[i]表示第i节点到满足结果的期望。

i为叶子节点 dp[i] = p1i*dp[1]+p2i*dp[fa[i]]+p3i*exit(exit==0)

这样可以多开两个数组存两个未知数的系数。

i为非叶子节点 dp[i] = p1i*dp[1]+p2i*1/k*dp[v](v与i相连的节点,共有K个)+p3i*exit。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 #include<vector>
11 using namespace std;
12 #define N 100010
13 #define LL long long
14 #define INF 0xfffffff
15 const double eps = 1e-10;
16 const double pi = acos(-1.0);
17 const double inf = ~0u>>2;
18 vector<int>ed[N];
19 double dp[N],p[N][3];
20 double o[N][2];
21 int flag;
22 void dfs(int u,int pre)
23 {
24     if(!flag) return ;
25     int i;
26     dp[u] = p[u][2];
27     o[u][0] = p[u][2];
28     o[u][1] = p[u][0];
29     int k = ed[u].size();
30     double pp = 0;
31     for(i = 0; i < k ; i++)
32     {
33         int v = ed[u][i];
34         if(v==pre) continue;
35         dfs(v,u);
36         dp[u]+=p[u][2]/k*dp[v];
37         o[u][1]+=p[u][2]/k*o[v][1];
38         pp+=p[u][2]/k*o[v][0];
39     }
40     if(u==1)
41     {
42         if(fabs(1-(o[u][1]+pp))>eps)
43         dp[u] = dp[u]/(1-(o[u][1]+pp));
44         else
45         flag = 0;
46         return;
47     }
48     if(fabs(1-pp)>eps)
49     {
50         dp[u] = (dp[u])/(1-pp);
51         o[u][1] = (o[u][1])/(1-pp);
52         o[u][0] = p[u][2]/k/(1-pp);
53     }
54     else
55     {
56         flag = 0;
57         return ;
58     }
59 }
60 int main()
61 {
62     int i,j,t,n;
63     int kk = 0;
64     cin>>t;
65     while(t--)
66     {
67         memset(dp,0,sizeof(dp));
68         memset(o,0,sizeof(o));
69         scanf("%d",&n);
70         flag = 1;
71         for(i = 1 ;i <= n ;i++)
72         ed[i].clear();
73         for(i = 1; i < n ;i++)
74         {
75             int u,v;
76             scanf("%d%d",&u,&v);
77             ed[u].push_back(v);
78             ed[v].push_back(u);
79         }
80         for(i = 1; i <=n ;i++)
81         {
82             int x,y;
83             scanf("%d%d",&x,&y);
84             p[i][0] = x/100.0;
85             p[i][1] = y/100.0;
86             p[i][2] = 1-p[i][1]-p[i][0];
87         }
88         dfs(1,-1);
89         printf("Case %d: ",++kk);
90         if(flag)
91         printf("%f
",dp[1]);
92         else
93         puts("impossible");
94     }
95     return 0;
View Code

第十四题--HDU 4418 Time travel(高斯消元求期望)

这个题意吧有点难理解。。是这个时光机每次可以走1-m步 概率分别为p[i]。

为了好做,可以加n-2个点统一方向, 0 1 2 3 2 1

这样dp[i] = (dp[i+1]+1)*p[i+1]+(dp[i+2]+2)*p[i+2]+...(dp[i+m]+m)*p[i+m];

这样会发现无论你倒推还是正推都无法减少未知数,不过可以列出来n-2个方程,n-2个未知数,高斯消元。

需要先bfs出是否能够达到,然后保留能够达到的点。

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stdlib.h>
  6 #include<vector>
  7 #include<cmath>
  8 #include<queue>
  9 #include<set>
 10 using namespace std;
 11 #define N 205
 12 #define LL long long
 13 #define INF 0xfffffff
 14 const double eps = 1e-8;
 15 const double pi = acos(-1.0);
 16 const double inf = ~0u>>2;
 17 double p[N],a[N][N],ans[N];
 18 int n,m,y,x,d,dis[N],g;
 19 int zn;
 20 bool vis[N];
 21 void gauss(int zw,int zr)
 22 {
 23     int i,j,k,g = 0;
 24     for(k = 0 ; k < zw && g < zr; k++,g++)
 25     {
 26         i = k;
 27         for(j = k+1 ; j <= zw ; j++)
 28         {
 29             if(fabs(a[j][g])>fabs(a[i][g]))
 30             i = j;
 31         }
 32         if(fabs(a[i][g])<eps)
 33         {
 34             continue;
 35         }
 36         if(i!=k)
 37         for(j = k ;j <= zr ; j++)
 38         swap(a[i][j],a[k][j]);
 39         for(i = k+1 ; i <= zw ; i++)
 40         {
 41             if(fabs(a[i][k])<eps) continue;
 42             double s = a[i][g]/a[k][g];
 43             a[i][g] = 0.0;
 44             for(j = g+1 ; j <= zr; j++)
 45                 a[i][j] -= s*a[k][j];
 46         }
 47     }
 48     for(i = zw ; i >= 0 ; i--)
 49     {
 50         if(fabs(a[i][i])<eps) continue;
 51         double s = a[i][zn];
 52         for(j = i+1 ; j <= zw ;j++)
 53         s-=a[i][j]*ans[j];
 54         ans[i] = s/a[i][i];
 55     }
 56 }
 57 int bfs()
 58 {
 59     int i;
 60     queue<int>q;
 61     memset(vis,0,sizeof(vis));
 62     q.push(x);
 63     vis[x] = 1;
 64     int ff = 0;
 65     while(!q.empty())
 66     {
 67         int u = q.front();
 68         q.pop();
 69         if(u==y||zn-u==y)
 70         {
 71             ff = 1;
 72             continue;
 73         }
 74         for(i = 1; i <= g; i++)
 75         {
 76             int v = (u+dis[i])%zn;
 77             if(!vis[v])
 78             {
 79                 vis[v] = 1;
 80                 q.push(v);
 81             }
 82         }
 83     }
 84     return ff;
 85 }
 86 int main()
 87 {
 88     int t,i,j;
 89     cin>>t;
 90     while(t--)
 91     {
 92         memset(a,0,sizeof(a));
 93         memset(ans,0,sizeof(ans));
 94         scanf("%d%d%d%d%d",&n,&m,&y,&x,&d);
 95         zn = 2*n-2;
 96         g = 0;
 97         double sum = 0;
 98         for(i= 1; i <= m; i++)
 99         {
100             int  pp;
101             scanf("%d",&pp);
102             if(pp>0)
103             {
104                 p[++g] = pp/100.0;
105                 dis[g] = i;
106                 sum+=p[g]*i;
107             }
108         }
109         if(d>0)
110         x = zn-x;
111         if(x==y)
112         {
113             puts("0.00");
114             continue;
115         }
116         if(!bfs())
117         {
118             puts("Impossible !");
119             continue;
120         }
121         for(i = 0 ; i < zn ; i++)
122         {
123             if(!vis[i]) continue;
124             a[i][i] = 1;
125             if(i==y||y==zn-i) continue;
126             for(j = 1 ; j <= g ;j++)
127             {
128                 int dd = (dis[j]+i)%zn;
129                 a[i][dd]-=p[j];
130             }
131             a[i][zn] += sum;
132         }
133         gauss(zn-1,zn);
134         printf("%.2f
",ans[x]);
135     }
136     return 0;
137 }
View Code

第十五题--HDU 4089 Activation(中等概率题)

这个题因为会出现循环求所以有求期望的感觉。

分情况看一下 dp[i][j]表示队里有i个人 他在第j的位置到最终结果的概率。

j==1 dp[i][1] = p1*dp[i][1]+p2*dp[i][i]+p4.

k>=j>1 dp[i][j] = p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1]+p4;

j>k  dp[i][j] = p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1];

因为一个i循环里面只有一个dp[i][i]事未知的,可以开一个一维数组保存dp[i][j]里面还有dp[i][i]的系数。

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 using namespace std;
11 #define N 2010
12 #define LL long long
13 #define INF 0xfffffff
14 const double eps = 1e-8;
15 const double pi = acos(-1.0);
16 const double inf = ~0u>>2;
17 double dp[N][N],o[N];
18 int main()
19 {
20     int i,j,n,m,k;
21     double p1,p2,p3,p4;
22     while(cin>>n>>m>>k)
23     {
24         scanf("%lf%lf%lf%lf",&p1,&p2,&p3,&p4);
25         memset(dp,0,sizeof(dp));
26         memset(o,0,sizeof(o));
27         int flag = 1;
28         if(fabs(1-p2-p1)<eps)
29         flag = 0;
30         else
31         dp[1][1] = p4/(1-p2-p1);
32         for(i = 2 ;i <= n ;i++)
33         {
34             o[0] = 0;
35             for(j = 1 ; j <= i; j++)
36             {
37                 if(j<=k)
38                 {
39                     if(j==1)
40                     {
41                         dp[i][j]+=p4;
42                         o[j] = p2;
43                     }
44                     else
45                     {
46                         dp[i][j] += p4+p2*dp[i][j-1]+p3*dp[i-1][j-1];
47                         o[j] = p2*o[j-1];
48                     }
49                 }
50                 else
51                 {
52                    dp[i][j]+= p2*dp[i][j-1]+p3*dp[i-1][j-1];
53                    o[j] = p2*o[j-1];
54                 }
55                 if(j==i)
56                 {
57                     if(fabs(1-p1-o[j])<eps)
58                     {
59                         flag = 0;
60                         break;
61                     }
62                     dp[i][j] = dp[i][j]/(1-p1-o[j]);
63                 }
64                 else
65                 {
66                     if(fabs(1-p1-o[j])<eps)
67                     {
68                         flag = 0;
69                         break;
70                     }
71                     dp[i][j] = dp[i][j]/(1-p1);
72                     o[j] = o[j]/(1-p1);
73                 }
74             }
75             if(!flag) break;
76             for(j = 1;j < i ;j++)
77             dp[i][j]+=dp[i][i]*o[j];
78         }
79         if(flag)
80         printf("%.5f
",dp[n][m]);
81         else
82         printf("%.5f
",0.0);
83     }
84     return 0;
85 }
View Code

第十六题--ZOJ 3380 Patchouli's Spell Cards(中等题)

这题没有推出来。。。 组合题,

dp[i,j]  表示用前i个数字在m个里放了j个位置,这些数字不一定都有用到
   dp[i,j] = ∑ dp[i-1,j-k]*C[m-(j-k),k]          0≤k≤j , k<l
   最后答案为dp[n,m]

个人认为做法很棒。。

题解参照

 1 import java.text.*;
 2 import java.io.*;
 3 import java.util.*;
 4 import java.math.*;
 5 import java.applet.*;
 6 public class Main 
 7 {
 8     public static void main(String[] args)
 9     {
10         Scanner  cin = new Scanner(System.in);
11         BigInteger [][]dp = new BigInteger[105][105];
12         BigInteger o = BigInteger.valueOf(0);
13         BigInteger [][]c = new BigInteger[105][105];
14         int n,m,i,j,l,k;
15         for(i=0;i<101;i++)c[i][0]=c[i][i]=BigInteger.valueOf(1);
16             for(i=2;i<101;i++){
17                     for(j=1;j<i;j++)
18                         c[i][j]=c[i-1][j-1].add(c[i-1][j]);
19                 }
20         while(cin.hasNext())
21         {
22             m = cin.nextInt();
23             n = cin.nextInt();
24             l = cin.nextInt();
25             BigInteger s1 ,s2 = BigInteger.valueOf(0);
26             s1 = BigInteger.valueOf(n);
27             s1 = s1.pow(m);
28             if(l>m)
29             {
30                 System.out.println("mukyu~");
31                 continue;
32             }
33             else if(l>m/2)
34             {
35                 for(i=l;i<=m;i++)
36                 {
37                     s2=s2.add(c[m][i].multiply( BigInteger.valueOf(n-1).pow(m-i) ));
38                 }
39                 s2=s2.multiply(BigInteger.valueOf(n));
40             }
41             else
42             {
43                 for(i = 0; i <= n ;i++)
44                     for(j = 0; j <= m; j++)
45                             dp[i][j] = o;
46                 dp[0][0] = BigInteger.ONE;
47                 for(i = 1; i <= n ;i++)
48                 {
49                     for(j = 0; j <= m ;j++)
50                     {
51                         for(k = 0; k <= Math.min(j, l-1) ;k++)
52                         dp[i][j] = dp[i][j].add(dp[i-1][j-k].multiply(c[m-(j-k)][k]));
53                     }
54                 }
55                 
56                 s2 = dp[n][m];
57                 s2 = s1.subtract(s2);
58             }
59             BigInteger gc = s2.gcd(s1);
60             System.out.println(s2.divide(gc)+"/"+s1.divide(gc));
61         }
62     }
63 }
View Code
原文地址:https://www.cnblogs.com/shangyu/p/3644545.html