noip2016 换教室

题目链接:Click here

Solution:

概率与期望,首先就应该想到dp,dp的原则就是不行就加一维

那么我们就能想到\(f[i][j][0/1]\)表示现在是第\(i\)节课,已经申请了\(j\)次,\(0/1\)表示这节课有没有申请

因为是最短距离,所以我们要先跑一遍\(Floyd\)求出两点之间的最短距离

然后转移的话,比较麻烦,不过很好想,就不再赘述,具体见代码

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+1;
const int V=301;
int n,v,m,e;
double f[N][N][2],pr[N];
int dis[V][V],a[N],b[N];
double ans=1111111111;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}int main(){
    memset(dis,0x3f,sizeof(dis));
    n=read(),m=read(),v=read(),e=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++) b[i]=read();
    for(int i=1;i<=n;i++) scanf("%lf",&pr[i]);
    for(int i=1;i<=e;i++){
        int x=read(),y=read();
        int val=read();
        if(val<dis[x][y]){
            dis[x][y]=val;
            dis[y][x]=val;
        }
    }
    for(int k=1;k<=v;k++)
        for(int i=1;i<=v;i++)
            for(int j=1;j<=v;j++)
                if(dis[i][k]+dis[k][j]<dis[i][j])
                    dis[i][j]=dis[i][k]+dis[k][j];
    for(int i=1;i<=v;i++) dis[i][i]=0;
    for(int i=2;i<=n;i++){
        f[i][0][0]=f[i-1][0][0]+(double)dis[a[i-1]][a[i]];
        for(int j=1;j<=min(i,m);j++){
            f[i][j][0]=f[i][j][1]=1e10;
            if(j<i){
                f[i][j][0]=(f[i-1][j][0]+(double)dis[a[i-1]][a[i]]);
                f[i][j][0]=min(f[i][j][0],(f[i-1][j][1]+(1.0-pr[i-1])*(double)dis[a[i-1]][a[i]]+pr[i-1]*(double)dis[b[i-1]][a[i]]));
            }
            f[i][j][1]=(f[i-1][j-1][0]+pr[i]*(double)dis[a[i-1]][b[i]]+(1-pr[i])*(double)dis[a[i-1]][a[i]]);
            if(j==1) continue;
            double tmp=f[i-1][j-1][1];tmp+=pr[i-1]*pr[i]*(double)dis[b[i-1]][b[i]];
            tmp+=pr[i-1]*(1-pr[i])*(double)dis[b[i-1]][a[i]];tmp+=(1-pr[i-1])*pr[i]*(double)dis[a[i-1]][b[i]];
            tmp+=(1-pr[i-1])*(1-pr[i])*(double)dis[a[i-1]][a[i]];f[i][j][1]=min(f[i][j][1],tmp);
        }
    }ans=f[n][0][0];
    for(int i=1;i<=m;i++)
        ans=min(ans,min(f[n][i][1],f[n][i][0]));
    printf("%.2lf\n",ans);
    return 0;
}
posted @ 2019-09-18 10:27  DQY_dqy  阅读(102)  评论(0编辑  收藏  举报