期望DP入门(p1850换教室)
第一个,期望dp所有的情况一定要考虑好,每个现状态都由前一个状态转移而来,所以无论是前一个状态通过怎样的方式,两状态的起点终点如何,都应加在一起。此题关系到前一个是否成功和后一个是否成功,分别为
i-1决定换教室,i决定换教室时 (i-1成功换教室+i失败换教室) (i-1成功换教室+i成功换教室) (i-1失败换教室+i失败换教室) (i-1失败换教室+i成功换教室)
i-1决定换教室,i决定不换教室(i-1成功换教室+i不换教室) (i-1失败换教室+i不换教室)
i-1决定不换教室,i决定换教室 (i-1不换教室+i成功换教室) (i-1不换教室+i失败换教室)
i-1决定不换教室,i决定不换教室 (i-1不换教室+i不换教室)
第二个,memset是绝对tmd不能用在double型数组上的。你会si掉。
第三个,判重边邻接矩阵可以简单这样搞:dis[x][y]=dis[y][x]=min(z,dis[x][y]);如果遇见vector或链式前向星或邻接矩阵都可以:map <pair<int,int>,bool> q;if(q[make_pair(a,b)]) continue;
第四个, double型的读入为%lf而非%llf。(被坑惨了)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n,m,v,e,dis[302][302],a[2003],b[2003],x,y,z; double k[2003],a2,a3,f[2003][2003][2]; void foll(){ for(int k=1;k<=v;k++) for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; } void DP(){ for(int i=2;i<=n;i++){ for(int j=0;j<=min(i,m);j++){ int m1=dis[a[i-1]][a[i]],m2=dis[a[i-1]][b[i]],m3=dis[b[i-1]][a[i]],m4=dis[b[i-1]][b[i]]; f[i][j][0]=min(f[i-1][j][1]+m3*k[i-1]+m1*(1-k[i-1]),f[i-1][j][0]+m1); if(j>=1) f[i][j][1]=min(f[i-1][j-1][1]+m4*k[i-1]*k[i]+m2*(1-k[i-1])*k[i]+m1*(1-k[i-1])*(1-k[i])+m3*k[i-1]*(1-k[i]),f[i-1][j-1][0]+dis[a[i-1]][b[i]]*k[i]+dis[a[i-1]][a[i]]*(1-k[i])); } } } int main(){ scanf("%d%d%d%d",&n,&m,&v,&e); for(int i=1;i<=300;i++) for(int j=1;j<=300;j++) dis[i][j]=99999999; for(int i=1;i<=300;i++) dis[i][i]=0; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) f[i][j][1]=f[i][j][0]=99999999; f[1][0][0]=f[1][1][1]=f[1][1][0]=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++) scanf("%lf",&k[i]); for(int i=1;i<=e;i++){ scanf("%d%d%d",&x,&y,&z); dis[x][y]=dis[y][x]=min(z,dis[x][y]); } foll(); DP(); double ans=99999999; for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][1],f[n][i][0])); printf("%.2lf",ans); return 0; }