[noip2016]换教室

传送门

期望dp

首先\(floyd\)求出最短路\(mp[i][j]\)(不会的右转百度)

然后考虑dp

\(f[ i ][ j ] [ k ]\) :考虑前\(i\)个点,申请换了\(j\)次教室,然后第\(i\)次有没有申请 其中\(k=0,1\),

所以转移方程就比较显然了,具体看代码吧。。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define write(x) printf("%d\n",x)
#define maxn 2005
int n,m,v,e,c[maxn],d[maxn],mp[305][305];
double f[maxn][maxn][2],p[maxn];
int main(){
    //freopen("testdata.in","r",stdin);
    //freopen("out.out","w",stdout);

    read(n),read(m),read(v),read(e);int x,y,z;
    for(int i=1;i<=v;i++) for(int j=1;j<=v;j++) mp[i][j]=1e9;
    for(int i=1;i<=n;i++) read(c[i]);
    for(int i=1;i<=n;i++) read(d[i]);
    for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
    for(int i=1;i<=e;i++) read(x),read(y),read(z),mp[x][y]=mp[y][x]=min(mp[x][y],z);

    for(int k=1;k<=v;k++) 
    for(int i=1;i<=v;i++)
        for(int j=1;j<i;j++)
        mp[i][j]=mp[j][i]=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=1;i<=n;i++) for(int j=0;j<=m;j++) f[i][j][0]=f[i][j][1]=1e9;
    f[1][1][1]=f[1][0][0]=0;
    for(int i=2;i<=n;i++){
    f[i][0][0]=f[i-1][0][0]+mp[c[i-1]][c[i]];
    for(int j=1;j<=min(i,m);j++){
        f[i][j][0]=min(f[i-1][j][0]+mp[c[i-1]][c[i]],f[i-1][j][1]+mp[c[i-1]][c[i]]*(1.0-p[i-1])+mp[d[i-1]][c[i]]*p[i-1]);
        f[i][j][1]=min(f[i-1][j-1][0]+mp[c[i-1]][c[i]]*(1.0-p[i])+mp[c[i-1]][d[i]]*p[i],
               f[i-1][j-1][1]+mp[c[i-1]][c[i]]*(1.0-p[i-1])*(1.0-p[i])+mp[c[i-1]][d[i]]*(1.0-p[i-1])*p[i]+
               mp[d[i-1]][c[i]]*p[i-1]*(1.0-p[i])+mp[d[i-1]][d[i]]*p[i-1]*p[i]);
    }
    }

    double ans=1e17;
    for(int i=0;i<=m;i++) ans=min(ans,min(f[n][i][0],f[n][i][1]));
    printf("%.2lf\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hbyer/p/9637435.html