51nod 1450 闯关游戏

\(\mathcal Link\)

考虑什么是最优策略。

先把每一关都打通,然后按 \(Y\) 从大到小打到二星。

换句话说,将 \(Y\) 从小到大排一下,考虑前面若干关打过去,直到某关开始每次二星。

然后期望 DP。

为了模拟决策过程,必须从 \(Y\) 大到 \(Y\) 小。(因为 \(Y\) 小是初状态 )

\[f(i,j)=\begin{cases} \max(s_i,\frac{1}{P(a_i>0)}+P(a_i=1|a_i>0)\times f(i-1,j-1)+P(a_i=2|a_i>0)\times f(i-1,j-2)) & i\leqslant j \\ f(i,i) & i>j \end{cases}\]

其中 \(s_i=\sum\limits_{j=1}^i \dfrac{1}{P(a_i=2)}\)

后一种状态是要保证通关。

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
    x=0;int w=0;char c=GetC();
    for(;!isdigit(c);w|=c=='-',c=GetC());
    for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
    if(w) x=-x;
    return in;
}
const int N=2e3+5;
struct qwq{
    int x,y;
}a[N];
double dp[N][N<<1];
bool operator <(qwq x,qwq y){return x.y>y.y;}
const double oo=1e9;
double s[N];
int main(){
    int n,m;io>>n>>m;
    for(int i=1;i<=n;++i) io>>a[i].x>>a[i].y;
    sort(a+1,a+n+1);
    for(int i=0;i<=n;++i)
        for(int j=0;j<=m;++j)
            dp[i][j]=oo;
    dp[0][0]=0;
    for(int i=1;i<=n;++i){
        s[i]=s[i-1]+1000.0/a[i].y;
    }
    for(int i=1;i<=n;++i){
        for(int j=i;j<=m;++j){
            dp[i][j]=min(
                dp[i][j],1000.0/(a[i].x+a[i].y)+1.0*a[i].x/(a[i].x+a[i].y)*dp[i-1][j-1]
                +1.0*a[i].y/(a[i].x+a[i].y)*dp[i-1][max(0,j-2)]);
            if(2*i>=j) dp[i][j]=min(dp[i][j],s[i]);
        }
        for(int j=i-1;~j;--j){
            dp[i][j]=dp[i][i];
        }
    }
    printf("%lf\n",dp[n][m]);
    return 0;
}

注意:这玩意虽然有 \(\max\),也长得跟个 DP 样的,但它是对决策过程的模拟。也就是说,这个东西本质上是个贪心。(困扰了我一段时间)

posted @ 2022-11-05 10:59  pref_ctrl27  阅读(23)  评论(0编辑  收藏  举报