【解題報告】【概率DP入門】 P1850 換教室
阿新 • • 發佈:2020-07-17
這道題是一道非常基本的期望的題目,我們只需要抓住關鍵,就是我們遞推直接進行DP就可以了,至於我們的最短路部分,因為資料並不是非常的大,所以說我們直接使用弗洛伊德演算法即可。然後根據期望的定義,我們使用期望等於概率乘上價值進行計算即可,然後使用刷表法每次判最小進行遞推即可。
因為時間原因我這裡不詳細講解,這裡有一篇寫的非常好的部落格推薦給大家。
連結:NOIP2016換教室
本人AC程式碼:
#include<bits/stdc++.h> using namespace std; const int N=2e3+5; const double inf=0x7fffffff; int n,m,v,e,c[N],d[N],mp[305][305]; double k[N],dp[N][N][2]; void init() { memset(mp,63,sizeof(mp)); scanf("%d%d%d%d",&n,&m,&v,&e); for(int i=1;i<=n;++i) scanf("%d",&c[i]); for(int i=1;i<=n;++i) scanf("%d",&d[i]); for(int i=1;i<=n;++i) scanf("%lf",&k[i]); for(int i=1;i<=e;++i) { int x,y,z; scanf("%d%d%d",&x,&y,&z); mp[x][y]=mp[y][x]=min(mp[y][x],z); } for(int k=1;k<=v;++k) for(int i=1;i<=v;++i) for(int j=1;j<=v;++j) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]); for(int i=1;i<=v;++i) mp[i][i]=mp[i][0]=mp[0][i]=0; for(int i=0;i<=n;++i) for(int j=0;j<=m;++j) dp[i][j][0]=dp[i][j][1]=inf; dp[1][0][0]=dp[1][1][1]=0; } int main() { init(); for(int i=2;i<=n;++i) { dp[i][0][0]=dp[i-1][0][0]+mp[c[i-1]][c[i]]; for(int j=1;j<=min(i,m);++j) { int c1=c[i-1],c2=d[i-1],c3=c[i],c4=d[i]; dp[i][j][0] = min(dp[i][j][0],min(dp[i-1][j][0]+mp[c1][c3],dp[i-1][j][1]+mp[c1][c3]*(1-k[i-1])+mp[c2][c3]*k[i-1])); dp[i][j][1] = min(dp[i][j][1],min(dp[i-1][j-1][0]+mp[c1][c3]*(1-k[i])+mp[c1][c4]*k[i],dp[i-1][j-1][1]+mp[c1][c3]*(1-k[i-1])*(1-k[i])+mp[c1][c4]*(1-k[i-1])*k[i]+mp[c2][c3]*k[i-1]*(1-k[i])+mp[c2][c4]*k[i-1]*k[i])); } } double ans=inf; for(int i=0;i<=m;++i)ans=min(ans,min(dp[n][i][0],dp[n][i][1])); printf("%.2lf",ans); return 0; }