51nod 1450 闯关游戏
考虑什么是最优策略。
先把每一关都打通,然后按 \(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 样的,但它是对决策过程的模拟。也就是说,这个东西本质上是个贪心。(困扰了我一段时间)