- 题目链接: UVALive - 7527 Funfair
- 题意: 给定n个游戏,从中选取k种游戏去玩,玩家的金钱初始值为x. 假设玩第i个游戏之前,拥有的金钱为x0, 则在第i个游戏中若胜利,则金钱变成x0+ai, 否则金钱变成 (1-li)*x0. 问: 玩完k个游戏后,金钱最大值为多少.(即求期望最大值)
- 给定, n, k, x
- n行,第i行输入第i个游戏的ai, li, pi, (pi表示赢的概率)
- 解法:
- 假设当前金钱为x, 则玩完第i个游戏,金钱期望 = ( x + ai ) * p i + ( 1 - l i ) * x * ( 1 - pi );
- 上述式子 = [ (1-li) * (1-pi) +pi ] * x + ai*pi;
- 若仅在任意两个游戏之间考虑, 即考虑i, j. 则 可以通过先玩i再玩j 和 先玩j再玩i 两种可能的期望大小(将上述式子代入计算,可消除x的影响),确定i, j在最终选取的k个游戏中的先后顺序。故可先给游戏按照上述规则排序,再进行dp.
- dp方程为: dp[i] = max( dp[i], [ (1-li) * (1-pi) +pi ] * dp[i-1] + ai*pi (1 < = i < = n)
- dp[0] = x , 初始金钱数.
- 利用滚动数组去求解,可降低空间复杂度.
- 滚动数组原理: 由于dp方程中dp[i]仅与dp[i-1] (即上一次求解的结果)有关,假设我们已经执行完i-1下的情况, 那么此时dp[1 到 k]均属于i-1下求解的答案,而在i的情况, 每次从k -> 1, 这样保证每次的dp[i-1]均为上次求解结果,用此结果来更新当前的dp[i]。
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i=a; i<=b; ++i)
#define repp(i, b, a) for(int i=b; i>=a; --i)
using namespace std;
const int maxn = 1e2+7;
struct node{
double a, l , p;
}g[maxn];
bool cmp(node a, node b){
return a.a*a.p*b.l*(b.p-1) > b.a*b.p*a.l*(a.p-1);
}
double dp[maxn];
int main(){
double x;
int n, k;
while(~scanf("%d %d %lf", &n, &k, &x)){
if(!n && !k && !x) break;
rep(i, 1, n) {
scanf("%lf %lf %lf", &g[i].a, &g[i].l, &g[i].p);
g[i].l/=100.0;
g[i].p/=100.0;
}
sort(g+1, g+1+n, cmp);
memset(dp, 0, sizeof(dp));
dp[0] = x;
rep(i, 1, n){
repp(j, k, 1){
dp[j] = max(dp[j], ((1-g[i].l)*(1-g[i].p)+g[i].p)*dp[j-1]+g[i].a*g[i].p);
}
}
printf("%.2lf\n", dp[k]);
}
return 0;
}