HOJ_13828 Funfair

首先,附队长大大队的博客,里面也有相关题目详解哦

队长大大队的博客:http://www.cnblogs.com/MeowMeowMeow/

队长大大队的这题的题解:http://www.cnblogs.com/MeowMeowMeow/p/7299208.html


Funfair
Time Limit: 10000ms, Special Time Limit:25000ms, Memory Limit:65536KB
Total submit users: 7, Accepted users: 6
Problem 13828 : Special judge
Problem description
We are going to a funfair where there are n games G1,...,Gn. We want to play k games out of the n games, and we can choose the order in which we play them—note that we cannot play any game more than once. We have to specify these k games and their order before starting any game.
At each point in time, we have some amount of money, which we use in playing the games. At the beginning, we have x0 Oshloobs of money. If before playing game Gi, we have x Oshloobs and we win in Gi, our money increases to x+Ai for some Ai ⩾ 0. If we have x Oshloobs before playing game Gi and we lose in Gi, we lose Li percent of x. The probability that we win game Gi (independently of other games) is Pi percents.
The goal is to play k of the games in such an order to maximize the expected amount of money we end up with after playing all k selected games in that order.

Input
There are multiple test cases in the input. The first line of each test case contains three space-separated integers n, k, and x0 (1 ⩽ k ⩽ n ⩽ 100, 0 ⩽ x0 ⩽ 106). Each of the next n lines specifies the properties of game Gi with three space-separated integers Ai, Li, and Pi (0 ⩽ Ai,Li,Pi ⩽ 100). The input terminates with a line containing 0 0 0 which should not be processed.

Output
For each test case, output a single line containing the maximum expected amount of our final money rounded to exactly two digits after the decimal point.

Sample Input
2 2 100
10 0 50
100 10 20
2 1 100
10 0 50
100 10 20
0 0 0 
Sample Output
117.00
112.00 
Problem Source

Asia Region, Tehran Site,Sharif University of Technology, 24?25 December 2015

题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=13828

提示点:DP + 排序

题意解析:给你n局游戏,从中选K局游戏来玩,对于每局游戏,给出三个数Ai,Li,Pi,分别表示如果赢了,在原来得分的基础上加上Ai,如果输了,在原来得分的基础上减去Li%的分数,对于每局游戏,赢得概率为Pi%,给出初始得分X0,要你求出K局游戏后,你的最终最高得分期望是多少?

解题思路:(为后续解题方便,暂时设Pi = Pi%,Li = Li%,设当前第i场游戏之前的得分为X‘)

对于第i局游戏:


概率 过后得分
Pi X’ + Ai
(1-Pi) X‘(1-Li)

所以对于第I局游戏的得分期望为X = Pi*(X’ + Ai) + (1-Pi)*X‘*(1-Li)= (1-Li + Pi*Li)*X’ + Pi*Ai;

所以对于每局游戏,我们不妨设有一个K=(1-Li+Pi*Li), b=Pi*Ai。对于每局游戏过后的得分就简化为了X=K*X‘+b。

解决了第i局游戏后的得分问题后,剩下还有两个问题,选择哪K局游戏和对于选择的K局游戏怎样排序才能使得最后得分最大;

首先来想排序问题,如果搞定了排序问题,那么就可以用动态规划来解决选取问题了。

对于两场游戏A1,A2,如果顺序为A1->A2,那么最后得分为A2.k(A1.k*x' + A1.b)+A2.b=A1.k*A2.k*x' + A2.k*A1.b + A2.b,如果顺序为A2->A1,那么最后得分为A1.k(A2.k*x' + A2.b)+A1.b=A1.k*A2.k*x' + A1.k*A2.b + A1.b,在这过程中,我们发现如果选取了K场游戏,最后的得分与X0没有关系,仅仅与排序有关,所以我们按照上述的规则(选择顺序为A1->A2还是A2->A1)将整个N局游戏排好序,之后如果选取了K局游戏,那么此时的序列一定就是使得分最大的序列。

接下来构造动态转移方程:(dp[i][j]代表选择i局游戏选到第J局时的最大得分)

if (i==j) dp[i][j] = A[j].k * dp[i-1][j-1] + A[j].b;

else  dp[i][j] = max(A[i][j-1] , A[j].k * dp[i-1][j-1] + A[j].b);

最后附上代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
struct node {
	double k;
	double b;
};
bool cmp(node a, node b) {
	return b.k*a.b + b.b > a.k*b.b + a.b;
}
node a[105];
int n,k;
double x0;
double dp[105][105];
void F() {
	for (int i=0; i<=n; ++i) dp[0][i]=x0;
	for (int i=1; i<=k; ++i) {
		for (int j=i; j<=n; ++j) {
			if (j==i) dp[i][j]=a[j].k * dp[i-1][j-1] + a[j].b;
			else {
				dp[i][j] = max(dp[i][j-1],a[j].k * dp[i-1][j-1] + a[j].b);
			}
		}
	}
}
int main() {
//	freopen("abc.txt", "r", stdin);
	double a1,l1,p1;
	while (scanf("%d%d%lf", &n, &k, &x0) && n) {
		if (n==0) break;
		for (int i=1; i<=n; ++i) {
			scanf("%lf%lf%lf", &a1, &l1, &p1);
			l1=l1/100.0;
			p1=p1/100.0;
			a[i].k=1-l1+l1*p1;
			a[i].b=a1*p1;
		}
		sort(a+1, a+1+n, cmp);
		F();
		printf("%.2lf\n", dp[k][n]);
	}
	return 0;
} 


猜你喜欢

转载自blog.csdn.net/xiaobai__lee/article/details/77248210
今日推荐