题目:https://www.luogu.org/problemnew/show/P1850
noip中比较难的期望dp。首先要求出两两最短路,由于300个点90000条边直接选用floyd;
然后就是dp了:
dp[ i ][ j ][ 0/1 ]表示”第i天已经提出j次申请,其中第i天不换/换教室“状态下最小期望路程 。
转移方程比较长但是好推:
dp[ i ][ 0 ][ 0 ] = dp[ i-1 ][ 0 ][ 0 ]+dis[ c[ i-1 ] ][ c[ i ] ];
dp[i][j][0] = min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1.0-g[i-1])+dis[d[i-1]][c[i]]*g[i-1]);
dp[i][j][1] = min(dp[i][j][1] , dp[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1.0-g[i])+dis[c[i-1]][d[i]]*g[i],dp[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1.0-g[i-1])*(1.0-g[i])+dis[d[i-1]][c[i]]*g[i-1]*(1.0-g[i])+dis[c[i-1]][d[i]]*(1.0-g[i-1])*g[i]+dis[d[i-1]][d[i]]*g[i-1]*g[i]);
有一点长
注意(1.0 - g[ i ])不能写成(1 - g[ i ])。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 2050 #define V 305 int n,m,v,E; int c[N],d[N],hed[V],cnt; double dis[V][V]; double g[N],dp[N][N][2]; int main() { scanf("%d%d%d%d",&n,&m,&v,&E); for(int i=1;i<=v;i++) { for(int j=1;j<=v;j++) { if(i!=j)dis[i][j]=1e12+5.0; } } 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",&g[i]); for(int f,t,w,i=1;i<=E;i++) { scanf("%d%d%d",&f,&t,&w); dis[f][t]=min(dis[f][t],(double)w); dis[t][f]=min(dis[t][f],(double)w); } 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]); for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) dp[i][j][0]=dp[i][j][1]=1e12+5.0; dp[1][0][0]=dp[1][1][1]=0.0; for(int i=2;i<=n;i++) { dp[i][0][0] = dp[i-1][0][0] + dis[c[i-1]][c[i]]; for(int j=1;j<=i&&j<=m;j++) { dp[i][j][0] = min(dp[i-1][j][0]+dis[c[i-1]][c[i]],dp[i-1][j][1]+dis[c[i-1]][c[i]]*(1.0-g[i-1])+dis[d[i-1]][c[i]]*g[i-1]); dp[i][j][1] = min(dp[i][j][1] , dp[i-1][j-1][0]+dis[c[i-1]][c[i]]*(1.0-g[i])+dis[c[i-1]][d[i]]*g[i]); dp[i][j][1] = min(dp[i][j][1] , dp[i-1][j-1][1]+dis[c[i-1]][c[i]]*(1.0-g[i-1])*(1.0-g[i])+dis[d[i-1]][c[i]]*g[i-1]*(1.0-g[i])+dis[c[i-1]][d[i]]*(1.0-g[i-1])*g[i]+dis[d[i-1]][d[i]]*g[i-1]*g[i]); } } double ans = 1e12; for(int i=0;i<=m;i++) ans = min(ans,min(dp[n][i][0],dp[n][i][1])); printf("%.2lf ",ans); return 0; }