全指望公式: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 }
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 }
【題意】:(%>_<%異次元殺陣有沒有)
有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 }
【題意】:有一我的被困在一個 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 }
【題意】:
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 }
【題意】:
【題意】:
【題意】: