洛谷1850 换教室

Luogu

分析

先跑 floyd 求出任意两个教室之间的最短路。注意处理一下自环和重边。

考虑 DP。设 $dp_{i,j,0/1}$ 表示前 $i$ 个教室,交了 $j$ 份申请,第 $i$ 个教室是否交了申请的最小期望体力。

先考虑 $dp_{i,j,0}$ 的转移。我们考虑上一个教室交没交申请,可以得到

$$ dp_{i,j,0}=\min\begin{cases}dp_{i-1,j,0}+dis_{c_{i-1},c_i}\\dp_{i-1,j,1}+(1-k_{i-1})dis_{c_{i-1},c_i}+k_{i-1}dis_{d_{i-1,c_i}}\end{cases} $$

$dp_{i,j,1}$ 的转移类似。其实是太长了 M_sea 懒得写了

然后答案就是 $\min_{i=0}^m\left\{dp_{n,i,0},dp_{n,i,1}\right\}$ 。

代码

// ===================================
//   author: M_sea
//   website: http://m-sea-blog.com/
// ===================================
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=2000+10,V=300+10;

int n,m,v,e;
int c[N],d[N]; double k[N];
int G[V][V];
double dp[N][N][2];

int main() {
    n=read(),m=read(),v=read(),e=read();
    for (re int i=1;i<=n;++i) c[i]=read();
    for (re int i=1;i<=n;++i) d[i]=read();
    for (re int i=1;i<=n;++i) scanf("%lf",&k[i]);
    memset(G,0x3f,sizeof(G));
    for (re int i=1;i<=v;++i) G[i][i]=0;
    for (re int i=1;i<=e;++i) {
        int u=read(),v=read(),w=read();
        G[u][v]=G[v][u]=min(G[u][v],w);
    }
    for (re int k=1;k<=v;++k)
        for (re int i=1;i<=v;++i)
            for (re int j=1;j<=v;++j)
                G[i][j]=min(G[i][j],G[i][k]+G[k][j]);
    memset(dp,127,sizeof(dp)); dp[1][0][0]=dp[1][1][1]=0;
    for (re int i=2;i<=n;++i) {
        dp[i][0][0]=dp[i-1][0][0]+G[c[i-1]][c[i]];
        for (re int j=1;j<=min(i,m);++j) {
            int a1=c[i-1],b1=d[i-1],a2=c[i],b2=d[i];
            dp[i][j][0]=min(
                dp[i-1][j][0]+G[a1][a2],
                dp[i-1][j][1]+(1-k[i-1])*G[a1][a2]+k[i-1]*G[b1][a2]
            );
            dp[i][j][1]=min(
                dp[i-1][j-1][0]+(1-k[i])*G[a1][a2]+k[i]*G[a1][b2],
                dp[i-1][j-1][1]+(1-k[i-1])*(1-k[i])*G[a1][a2]
                               +(1-k[i-1])*k[i]*G[a1][b2]
                               +k[i-1]*(1-k[i])*G[b1][a2]
                               +k[i-1]*k[i]*G[b1][b2]
            );
        }
    }
    double ans=1e100;
    for (re int i=0;i<=m;++i)
        ans=min(ans,min(dp[n][i][0],dp[n][i][1]));
    printf("%.2lf\n",ans);
    return 0;
}
最后修改:2019 年 10 月 21 日 04 : 56 PM

发表评论