P1850 换教室(期望dp)

题目传送门

题意: n n n节课,每节课在相同时间不同教室上( c [ i ] c[i] c[i] d [ i ] d[i] d[i]),总共有 v v v个教室, e e e条边,在学期开始之前,你可以向学校申请调换教室(由 c [ i ] c[i] c[i]换到 d [ i ] d[i] d[i]),第 i i i节课调换成功的概率是 k [ i ] k[i] k[i],你最多可以选择 m m m节课进行调换,并且不同课之间调换是否成功不受影响。我们想知道从第一节课的教室到第 n n n节课的教室,我们走的最短的路的期望是多少?

思路: 先用 F l o y d Floyd Floyd把每两个点之间的最短距离处理一下。然后我们用 f [ i ] [ j ] [ 0 / 1 ] f[i][j][0/1] f[i][j][0/1]表示处理完前 i i i节课,选择了 j j j节课申请调换,第 i i i节课是否申请(0/1)时的期望最短路径。那么我们就可以写出状态转移方程。

  1.     double d1=1.0*a[c[i-1]][c[i]];
        double d2=1.0*a[c[i-1]][d[i]];
        double d3=1.0*a[d[i-1]][c[i]];
        double d4=1.0*a[d[i-1]][d[i]];
    
  2. f [ i ] [ j ] [ 0 ] = m i n ( f [ i − 1 ] [ j ] [ 0 ] + 1.0 ∗ d 1 , f [ i − 1 ] [ j ] [ 1 ] + d 1 ∗ ( 1 − k [ i − 1 ] ) + d 3 ∗ k [ i − 1 ] ) ; f[i][j][0]=min(f[i-1][j][0]+1.0*d1,f[i-1][j][1]+d1*(1-k[i-1])+d3*k[i-1]); f[i][j][0]=min(f[i1][j][0]+1.0d1,f[i1][j][1]+d1(1k[i1])+d3k[i1]);

  3. f [ i ] [ j ] [ 1 ] = m i n ( f [ i − 1 ] [ j − 1 ] [ 0 ] + d 1 ∗ ( 1 − k [ i ] ) + d 2 ∗ k [ i ] , f [ i − 1 ] [ j − 1 ] [ 1 ] + d 1 ∗ ( 1 − k [ i − 1 ] ) ∗ ( 1 − k [ i ] ) + d 2 ∗ ( 1 − k [ i − 1 ] ) ∗ k [ i ] + d 3 ∗ k [ i − 1 ] ∗ ( 1 − k [ i ] ) + d 4 ∗ k [ i − 1 ] ∗ k [ i ] ) ; f[i][j][1]=min(f[i-1][j-1][0]+d1*(1-k[i])+d2*k[i],f[i-1][j-1][1]+d1*(1-k[i-1])*(1-k[i])+d2*(1-k[i-1])*k[i]+d3*k[i-1]*(1-k[i])+d4*k[i-1]*k[i]); f[i][j][1]=min(f[i1][j1][0]+d1(1k[i])+d2k[i],f[i1][j1][1]+d1(1k[i1])(1k[i])+d2(1k[i1])k[i]+d3k[i1](1k[i])+d4k[i1]k[i]);

最后找答案就很简单了。

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define lowbit(x) x&-x
#define pii pair<int,int>
#define ull unsigned long long
#define pdd pair<double,double>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
    int x=0,f=1;
    char ch=gc();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=gc();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=gc();
    }
    return x*f;
}
using namespace std;
const int N=3e4+666;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-7;
const double PI=acos(-1);

int c[N],d[N],a[333][333];
double k[N],f[2222][2222][2];
signed main()
{
    int n,m,v,e;
    cin>>n>>m>>v>>e;
    for(int i=1; i<=n; i++)
        cin>>c[i];
    for(int i=1; i<=n; i++)
        cin>>d[i];
    for(int i=1; i<=n; i++)
        cin>>k[i];
    for(int i=0; i<333; i++)
        for(int j=0; j<333; j++)
            a[i][j]=(i==j?0:inf);
    for(int i=0;i<2222;i++)
        for(int j=0;j<2222;j++)
            f[i][j][0]=f[i][j][1]=1e9;
    for(int i=1; i<=e; i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        a[x][y]=min(a[x][y],z);
        a[y][x]=min(a[y][x],z);
    }
    for(int p=1; p<=v; p++)
        for(int i=1; i<=v; i++)
            for(int j=1; j<=v; j++)
                a[i][j]=min(a[i][p]+a[p][j],a[i][j]);
    double res=1e9;
    f[1][0][0]=f[1][1][1]=0.0;
    for(int i=2; i<=n; i++)
    {
        for(int j=0; j<=min(i,m); j++)
        {
            double d1=1.0*a[c[i-1]][c[i]];
            double d2=1.0*a[c[i-1]][d[i]];
            double d3=1.0*a[d[i-1]][c[i]];
            double d4=1.0*a[d[i-1]][d[i]];
            f[i][j][0]=min(f[i-1][j][0]+1.0*d1,f[i-1][j][1]+d1*(1-k[i-1])+d3*k[i-1]);
            if(j!=0)
                f[i][j][1]=min(f[i-1][j-1][0]+d1*(1-k[i])+d2*k[i],f[i-1][j-1][1]+d1*(1-k[i-1])*(1-k[i])+d2*(1-k[i-1])*k[i]+d3*k[i-1]*(1-k[i])+d4*k[i-1]*k[i]);
        }
    }
    for(int i=0;i<=m;i++)
        res=min(res,min(f[n][i][0],f[n][i][1]));
    printf("%.2f\n",res);




    return 0;
}

期望dp和概率dp是两种不同的动态规划方法。 期望dp是指通过计算每个状态的期望值来求解最终的期望。在期望dp中,我们通常定义dp\[i\]表示在第i个状态时的期望值,然后通过状态转移方程来更新dp数组,最终得到最终状态的期望值。期望dp通常用于求解期望问题,例如求解骰子的期望点数、求解抽奖的期望次数等。 概率dp是指通过计算每个状态的概率来求解最终的概率。在概率dp中,我们通常定义dp\[i\]表示在第i个状态时的概率,然后通过状态转移方程来更新dp数组,最终得到最终状态的概率。概率dp通常用于求解概率问题,例如求解抛硬币出现正面的概率、求解从一副牌中抽到红心的概率等。 总结来说,期望dp和概率dp的区别在于它们所计算的是不同的值,期望dp计算的是期望值,而概率dp计算的是概率值。 #### 引用[.reference_title] - *1* [概率/期望dp专题](https://blog.csdn.net/qq_34416123/article/details/126585094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【动态规划】数学期望/概率DP/期望DP详解](https://blog.csdn.net/weixin_45697774/article/details/104274160)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值