「Luogu」1850 换教室

题意:原题在这

Little Yu的n个时间段上都有两节课同时进行,她一开始在dflt[i]教室,想去hope[i]教室,而申请通过概率为k[i],且总共有m次机会可以申请。

已知Yu的学校有v个教室,e条道路相互连通(无向图),每条路有一个代价。
求:申请哪几门课程能使Yu在教室之间乱跑的体力期望最小

思路:

1. dp[i][j][k]表示到第i个点,已经更改了j次,k=0这个点不更,k=1这个点更 的最小期望

2. memset不能初始化最大值会爆炸

3. dp转移方程过于麻烦详见代码注释

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define inf 999999999
#define maxm 305
#define maxn 2005
using namespace std;
int n,m,v,e;
double ans=inf;//一定要是inf,不能是0
int dflt[maxn],hope[maxn];//原教室和想去的教室
double dp[maxn][maxn][2],dis[maxm][maxm];
double k[maxn];//换教室的概率

void input()
{
    cin>>n>>m>>v>>e;
    for(int i=1;i<=n;i++) cin>>dflt[i];
    for(int i=1;i<=n;i++) cin>>hope[i];
    for(int i=1;i<=n;i++) cin>>k[i];

    for(int i=1;i<=v;i++)
    for(int j=1;j<i;j++)
    {
        dis[i][j]=inf;
        dis[j][i]=inf;
    }
    for(int i=1;i<=e;i++)
    {
        int f,g;double w;
        cin>>f>>g>>w;
        dis[f][g]=min(dis[f][g],w);
        dis[g][f]=dis[f][g];
    }
    
    for(int k=1;k<=v;k++)//Floyd跑一发两个教室间的距离
    for(int i=1;i<=v;i++)
    for(int j=1;j<i;j++)
    {
        if(dis[i][j]>dis[i][k]+dis[k][j])
        {
            dis[i][j]=dis[i][k]+dis[k][j];
            dis[j][i]=dis[i][j];
        }
    }
    return;
}

int main()
{
    input();
    for(int i=1;i<=n;i++)
    for(int j=0;j<=m;j++)
    for(int k=0;k<=1;k++)
    {
        dp[i][j][k]=inf; 
    }
//     memset(dp,inf,sizeof(dp));
    dp[1][0][0]=0.0;dp[1][1][1]=0.0;
    
    for(int i=2;i<=n;i++)
    for(int j=0;(j<=m)&&(j<=i);j++)
    {
        dp[i][j][0]=min(dp[i-1][j][0]+dis[dflt[i-1]][dflt[i]],
      //这个点不换:     上个点也不换
        dp[i-1][j][1]+dis[dflt[i-1]][dflt[i]]*(1-k[i-1])+dis[hope[i-1]][dflt[i]]*k[i-1]);
        //上个点没换成                                    上个点换了
        
        if(j>=1)
        {
            dp[i][j][1]=min(dp[i-1][j-1][0]+dis[dflt[i-1]][hope[i]]*k[i]+dis[dflt[i-1]][dflt[i]]*(1.0-k[i]),
            //这个点要换:   上个点没换       这个点换了                    这个点没换成
            dp[i-1][j-1][1]+dis[hope[i-1]][hope[i]]*k[i-1]*k[i]+
            //上个点和这个点都换了
            dis[hope[i-1]][dflt[i]]*k[i-1]*(1.0-k[i])+
            //上个点换了,这个点没换成
            dis[dflt[i-1]][hope[i]]*(1.0-k[i-1])*k[i]+
            //上个点没换,这个点换成了
            dis[dflt[i-1]][dflt[i]]*(1.0-k[i-1])*(1.0-k[i]));
            //两个点都没换
        }
    }
    
    for(int i=0;i<=m;i++)
    for(int j=0;j<=1;j++)
    {
        ans=min(ans,dp[n][i][j]);
    }
    printf("%.2lf",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LocaEtric/p/9614305.html