NOIp級的機率指望(然而我如今仍是須要推第二遍)。c++
能夠獲得很簡單的$dp$定義,$dp[i][j][0/1]$,考慮完前$i$個時間段,進行了$j$次申請,當前此次是否申請的最優指望。數組
剩下的轉移能夠直接分類討論:ide
dp[i][j][0]=min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+p[i-1]*dis[d[i-1]][c[i]]+(1-p[i-1])*dis[c[i-1]][c[i]]),因爲這一次咱們沒有申請,因此當上一次也沒有申請的時候只有一種狀況,從上個c到這個c,當上一次申請後,討論申請是否成功,轉移的距離隨着是否成功而變。spa
dp[i][j][1]=min(dp[i-1][j-1][0]+p[i]*dis[c[i-1]][d[i]]+(1-p[i])*dis[c[i-1]][c[i]],dp[i-1][j-1][1]+p[i-1]*p[i]*dis[d[i-1]][d[i]]+p[i-1]*(1-p[i])*dis[d[i-1]][c[i]]+(1-p[i-1])*p[i]*dis[c[i-1]][d[i]]+(1-p[i-1])*(1-p[i])*dis[c[i-1]][c[i]],式子很長,可是思想是同樣的,討論是否成功,來決定dis的下標選擇。code
dis數組能夠直接$Floyd$解出來。blog
有些小細節,點數300,邊數90000,明示重邊,注意$Floyd$不要打醜。get
最優決策$dp$注意初始化問題。it
代碼是最後一週寫的,徹底放飛自個人壓行,看看$dp$式子就完事了。(注意保護眼睛)event
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 inline int read(int sum=0,int f=1,char x=getchar()){ 6 while(x<'0' || x>'9'){ 7 if(x=='-') f=-1; x=getchar(); 8 }while(x>='0' && x<='9'){ 9 sum=sum*10+x-'0';x=getchar(); 10 }return sum*f; 11 } 12 13 int n,m,V,E,c[2050],d[2050],dis[305][305]; 14 double p[2050],dp[2050][2050][2],ans=1e14; 15 16 int main(){ 17 n=read(); m=read(); V=read(); E=read(); 18 for(int i=1; i<=n; ++i) c[i]=read(); for(int i=1; i<=n; ++i) d[i]=read(); for(int i=1; i<=n; ++i) scanf("%lf",p+i); 19 memset(dis,0x3f,sizeof(dis)); for(int i=1; i<=V; ++i) dis[i][i]=0; 20 for(int i=1,x,y,w; i<=E; ++i) x=read(), y=read(), w=read(), dis[x][y]=min(dis[x][y],w), dis[y][x]=min(dis[y][x],w); 21 for(int k=1; k<=V; ++k) for(int i=1; i<=V; ++i) for(int j=1; j<=V; ++j) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 22 memset(dp,88,sizeof(dp)); dp[0][0][0]=dp[0][0][1]=0; for(int i=0; i<=V; ++i) dis[i][0]=dis[0][i]=0; 23 for(int i=1; i<=n; ++i) for(int j=0; j<=min(i,m); ++j){ 24 dp[i][j][0]=min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+p[i-1]*dis[d[i-1]][c[i]]+(1.0-p[i-1])*dis[c[i-1]][c[i]]); 25 if(j) dp[i][j][1]=min(dp[i-1][j-1][0]+p[i]*dis[c[i-1]][d[i]]+(1.0-p[i])*dis[c[i-1]][c[i]],dp[i-1][j-1][1]+p[i-1]*p[i]*dis[d[i-1]][d[i]]+p[i-1]*(1.0-p[i])*dis[d[i-1]][c[i]]+(1.0-p[i-1])*p[i]*dis[c[i-1]][d[i]]+(1.0-p[i-1])*(1.0-p[i])*dis[c[i-1]][c[i]]); 26 } 27 for(int i=0; i<=m; ++i) ans=min(ans,min(dp[n][i][0],dp[n][i][1])); 28 printf("%.2lf",ans); return 0; 29 }