2014 summer day 6 機率dp

全指望公式:php

全機率公式:ios

POJ 2096ide

【題意】:oop

一個軟件有s個子系統,會產生n種bug。
某人一天發現一個bug,這個bug屬於某種bug,發生在某個子系統中。
求找到全部的n種bug,且每一個子系統都找到bug,這樣所要的天數的指望。
【分析】:須要注意的是:bug的數量是無窮大的,因此發現一個bug,出如今某個子系統的機率是1/s,
屬於某種類型的機率是1/n。spa

那麼dp[i][j]表示還要找到i個系統,還要找到j種病毒的機率。code

具體dp方程看代碼。但怎麼來講這個dp方程的正確性都怪怪的。blog

s,n<=1000get

【代碼】:博客

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 
 5 using namespace std;
 6 
 7 double dp[1005][1005];
 8 int S,N;
 9 int main(){
10     while(~scanf("%d%d",&N,&S)){
11         double n=N+0.0;
12         double s=S+0.0;
13         dp[S][N]=0;
14         for(int i=S;i>=0;i--){
15             for(int j=N;j>=0;j--){
16                 double ans=1;
17                 if (i==S && j==N) continue;
18                 if (i<S) ans+=dp[i+1][j]*(s-i)*j/(s*n);
19                 if (j<N) ans+=dp[i][j+1]*(n-j)*i/(s*n);
20                 if (i<S && j<N) ans+=dp[i+1][j+1]*(s-i)*(n-j)/(s*n);
21                 dp[i][j]=ans/(1.0-i*j/(s*n));
22             }
23         }
24         printf("%.4f\n",dp[0][0]);
25     }
26     return 0;
27 }
View Code

 

HDU 4405string

【題意】:

有n個格子,擲色子的擲出的數目就是你一次到移動格數(1--6的點數)。
其中有m個飛行通道可讓你直接從第xi格飛到第yi格。
傳送中是連續的,並且不要投骰子
問你走到終點的指望是多少。

【分析】:

dp[i]:開始時處於i位置時要走的指望步數。

一道狀態轉移要特判的dp,由於一旦從x點能夠直接到y點的話,則dp[x]=dp[y];

不然dp[i]=1/6*sigm(dp[i+1]...dp[i+6])+1,i>=N時dp[i]=1;

具體處理看代碼。

【代碼】:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 
 5 using namespace std;
 6 
 7 int N,M;
 8 int c[100010];
 9 double dp[100010];
10 int dfs(int i){
11     if (c[i]==i) return c[i];
12     else return dfs(c[i]);
13 }
14 int main(){
15     while(~scanf("%d%d",&N,&M)){
16         if (N==0 && M==0) break;
17         for(int i=0;i<=N;i++){
18             c[i]=i;
19         }
20         for(int i=1;i<=M;i++){
21             int x,y;
22             scanf("%d%d",&x,&y);
23             c[x]=y;
24         }
25         for(int i=0;i<=N;i++){
26             if (c[i]==i) continue;
27             else c[i]=dfs(i);
28         }
29         for(int i=N;i<=N+7;i++) {
30             dp[i]=0;
31             c[i]=i;
32         }
33         for(int i=N-1;i>=0;i--){
34             double ans=0;
35             if (c[i]!=i){
36                 dp[i]=dp[c[i]];
37                 continue;
38             }
39             for(int j=1;j<=6;j++) {
40                 int x=i+j;
41                 ans+=dp[c[x]];
42             }
43             ans=ans*(1/6.0)+1;
44             dp[i]=ans;
45         }
46         printf("%.4f\n",dp[0]);
47     }
48     return 0;
49 }
View Code

 

HDU 4035

【題意】:(%>_<%異次元殺陣有沒有)

有n個房間,由n-1條隧道連通起來,實際上就造成了一棵樹,
    從結點1出發,開始走,在每一個結點i都有3種可能:
        1.被殺死,回到結點1處(機率爲ki)
        2.找到出口,走出迷宮 (機率爲ei)
        3.和該點相連有m條邊,隨機走一條
    求:走出迷宮所要走的邊數的指望值。

 

【分析】:(按照kuangbin的博客推導了一遍,寫在本子上,無恥地將之分析粘過來)

    設 E[i]表示在結點i處,要走出迷宮所要走的邊數的指望。E[1]即爲所求。

    葉子結點:
    E[i] = ki*E[1] + ei*0 + (1-ki-ei)*(E[father[i]] + 1);
         = ki*E[1] + (1-ki-ei)*E[father[i]] + (1-ki-ei);

    非葉子結點:(m爲與結點相連的邊數)
    E[i] = ki*E[1] + ei*0 + (1-ki-ei)/m*( E[father[i]]+1 + ∑( E[child[i]]+1 ) );
         = ki*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei)/m*∑(E[child[i]]) + (1-ki-ei);

    設對每一個結點:E[i] = Ai*E[1] + Bi*E[father[i]] + Ci;

    對於非葉子結點i,設j爲i的孩子結點,則
    ∑(E[child[i]]) = ∑E[j]
                   = ∑(Aj*E[1] + Bj*E[father[j]] + Cj)
                   = ∑(Aj*E[1] + Bj*E[i] + Cj)
    帶入上面的式子得
    (1 - (1-ki-ei)/m*∑Bj)*E[i] = (ki+(1-ki-ei)/m*∑Aj)*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei) + (1-ki-ei)/m*∑Cj;
    由此可得
    Ai =        (ki+(1-ki-ei)/m*∑Aj)   / (1 - (1-ki-ei)/m*∑Bj);
    Bi =        (1-ki-ei)/m            / (1 - (1-ki-ei)/m*∑Bj);
    Ci = ( (1-ki-ei)+(1-ki-ei)/m*∑Cj ) / (1 - (1-ki-ei)/m*∑Bj);

    對於葉子結點
    Ai = ki;
    Bi = 1 - ki - ei;
    Ci = 1 - ki - ei;

    從葉子結點開始,直到算出 A1,B1,C1;

    E[1] = A1*E[1] + B1*0 + C1;
    因此
    E[1] = C1 / (1 - A1);
    若 A1趨近於1則無解...

【代碼】:

 1 /*
 2 
 3 */
 4 #include <iostream>
 5 #include <stdio.h>
 6 #include <math.h>
 7 #include <vector>
 8 #define eps 1e-10
 9 using namespace std;
10 vector<int>G[10010];
11 double A[10010];
12 double B[10010];
13 double C[10010];
14 double e[10010],k[10010],p[10010];
15 
16 int N,K;
17 bool dfs(int u,int fa){
18     int m=G[u].size();
19     double sumA=0,sumB=0,sumC=0;
20     for(int i=0;i<m;i++){
21         int v=G[u][i];
22         if (v==fa) continue;
23         if (!dfs(v,u)) return false;
24         sumB+=p[u]/m*B[v];
25         sumA+=p[u]/m*A[v];
26         sumC+=p[u]/m*C[v];
27     }
28     if (1-sumB<eps) return false;
29     A[u]=(k[u]+sumA)/(1-sumB);
30     B[u]=p[u]/m/(1-sumB);
31     C[u]=(p[u]+sumC)/(1-sumB);
32     return true;
33 }
34 int main(){
35     int t;
36     scanf("%d",&t);
37     for(int cas=1;cas<=t;cas++){
38         scanf("%d",&N);
39         int u,v;
40         for(int i=0;i<=N;i++) G[i].clear();
41         for(int i=0;i<N-1;i++){
42             scanf("%d%d",&u,&v);
43             G[u].push_back(v);
44             G[v].push_back(u);
45         }
46         for(int i=1;i<=N;i++){
47             scanf("%lf%lf",&k[i],&e[i]);
48             k[i]/=100;
49             e[i]/=100;
50             p[i]=1-k[i]-e[i];
51         }
52         printf("Case %d: ",cas);
53         if (dfs(1,-1)==false || (1-A[1]<eps)){
54             printf("impossible\n");
55         }else {
56             double ans=C[1]/(1-A[1]);
57             printf("%.6f\n",ans);
58         }
59     }
60     return 0;
61 }
View Code

 

HDU 3853

【題意】:有一我的被困在一個 R*C(2<=R,C<=1000) 的迷宮中,起初他在 (1,1) 這個點,迷宮的出口是 (R,C)。在迷宮的每個格子中,他能花費 2 個魔法值開啓傳送通道。假設他在 (x,y) 這個格子中,開啓傳送通道以後,有 p_lift[i][j] 的機率被送到 (x,y+1),有 p_down[i][j] 的機率被送到 (x+1,y),有 p_loop[i][j] 的機率被送到 (x,y)。問他到出口須要花費的魔法值的指望是多少。

【分析】:DP[i][j]表示如今處在(i,j)點時,須要花費的指望天數

dp[i][j]=mov0*dp[i][j]+mov1*dp[i][j+1]+mov2*dp[i+1][j]+2

寫出全指望公式,可是要防止除0的發生,即1-mov0<eps,特判跳過這點就好了。表示不能走到這一點

 即:

 for(int i=N;i>=1;i--){ for(int j=M;j>=1;j--){ if (vis[i][j]) continue; double ans=2; if (!vis[i][j+1]) ans+=mov[i][j][1]*dp[i][j+1]; if (!vis[i+1][j]) ans+=mov[i][j][2]*dp[i+1][j]; dp[i][j]=ans/(1-mov[i][j][0]); } }
【代碼】:
 1 /*
 2 
 3 */
 4 #include <iostream>
 5 #include <stdio.h>
 6 #include <math.h>
 7 #include <vector>
 8 #include <string.h>
 9 #define eps 1e-10
10 using namespace std;
11 //int a[][2]={{0,0},{0,1},{1,0}};
12 double dp[1004][1004];
13 double mov[1004][1004][3];
14 bool vis[1004][1004];
15 int N,M;
16 int main(){
17     while(~scanf("%d%d",&N,&M)){
18         memset(vis,false,sizeof(vis));
19         for(int i=1;i<=N;i++){
20             for(int j=1;j<=M;j++){
21                 for(int k=0;k<3;k++){
22                     scanf("%lf",&mov[i][j][k]);
23                     if (1-mov[i][j][0]<eps) vis[i][j]=true;
24                 }
25             }
26         }
27         //dp[i][j]=mov0*dp[i][j]+mov1*dp[i][j+1]+mov2*dp[i+1][j]+2;
28         //dp[N][M]=0;
29         //dp[1][1]=ans;
30         for(int i=0;i<=N+1;i++) dp[i][M+1]=0;
31         for(int i=0;i<=M+1;i++) dp[N+1][i]=0;
32         for(int i=N;i>=1;i--){
33             for(int j=M;j>=1;j--){
34                 if (vis[i][j]) continue;
35                 double ans=2;
36                 if (!vis[i][j+1]) ans+=mov[i][j][1]*dp[i][j+1];
37                 if (!vis[i+1][j]) ans+=mov[i][j][2]*dp[i+1][j];
38                 dp[i][j]=ans/(1-mov[i][j][0]);
39             }
40         }
41         printf("%.3f\n",dp[1][1]);
42     }
43     return 0;
44 }
View Code
 

POJ 3071

【題意】:

2^n支球隊按照競賽圖踢足球,
給你任意兩支球隊相互之間踢贏的機率,
求最後那支球隊最可能奪冠。

【分析】:每輪剩下的隊伍是必定的,並且到底和誰PK也是必定的,按競賽圖枚舉便可

//dp[i][j] = ∑dp[i-1][k]*p[j][k]*dp[i-1][j]
//k表示可能與j 比賽的隊伍,那麼k有哪些呢?
//當i=1時,和1
//當i=2時,和3,4
//當i=3時,和5,6,7,8
//就是 2^(i-1)+1---->2^(i)

【代碼】:

 1 /*
 2 題意:2^n支球隊按照競賽圖踢足球,
 3 給你任意兩支球隊相互之間踢贏的機率,
 4 求最後那支球隊最可能奪冠。
 5 */
 6 #include <iostream>
 7 #include <stdio.h>
 8 #include <math.h>
 9 #include <vector>
10 #include <string.h>
11 #define eps 1e-10
12 using namespace std;
13 //dp[i][j] = ∑dp[i-1][k]*p[j][k]*dp[i-1][j]
14 //k表示可能與j 比賽的隊伍,那麼k有哪些呢?
15 //當i=1時,和1
16 //當i=2時,和3,4
17 //當i=3時,和5,6,7,8
18 //就是 2^(i-1)+1---->2^(i)
19 double dp[10][150];
20 double p[150][150];
21 int N;
22 int main(){
23     while(~scanf("%d",&N)&& N!=-1){
24         for(int i=0;i<(1<<N);i++){
25             dp[0][i]=1;
26         }
27         for(int i=0;i<(1<<N);i++){
28             for(int j=0;j<(1<<N);j++){
29                 scanf("%lf",&p[i][j]);
30             }
31         }
32         for(int i=1;i<=N;i++){
33             for(int j=0;j<(1<<N);j++){
34                 dp[i][j]=0;
35                 for(int k=0;k<(1<<N);k++){
36                     if(((j>>(i-1))^1)==(k>>(i-1))){
37                     dp[i][j]+=dp[i-1][k]*dp[i-1][j]*p[j][k];
38 //                    cout<<i<<","<<j<<","<<k<<":"<<dp[i][j]<<endl;
39                     }
40                 }
41             }
42         }
43         double m=-1;
44         int ans=-1;
45         for(int i=0;i<(1<<N);i++){
46             if (dp[N][i]>m){
47                 m=dp[N][i];
48                 ans=i;
49             }
50         }
51         printf("%d\n",ans+1);
52     }
53     return 0;
54 }
View Code

 

SGU 495

【題意】:

ZOJ 3640

【題意】:

POJ 3744

【題意】:

相關文章
相關標籤/搜索