题目链接
http://acm.hust.edu.cn/vjudge/problem/17270
思路
要使数学期望最小,明显可以看出来概率越大的应该先选,因此先将所有c[i]按照概率从大到小排序后进行dp
定义状态d[i][x]:目前选到第i组,当前选择的元素的是第x个的数学期望
转移方程:
代码
#include <iostream>
#include <cstring>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <deque>
#include <bitset>
#include <algorithm>
using namespace std;
#define PI acos(-1.0)
#define LL long long
#define PII pair<int, int>
#define PLL pair<LL, LL>
#define mp make_pair
#define IN freopen("in.txt", "r", stdin)
#define OUT freopen("out.txt", "wb", stdout)
#define scan(x) scanf("%d", &x)
#define scan2(x, y) scanf("%d%d", &x, &y)
#define scan3(x, y, z) scanf("%d%d%d", &x, &y, &z)
#define sqr(x) (x) * (x)
#define pr(x) cout << #x << " = " << x << endl
#define lc o << 1
#define rc o << 1 | 1
#define pl() cout << endl
#define CLR(a, x) memset(a, x, sizeof(a))
#define FILL(a, n, x) for (int i = 0; i < n; i++) a[i] = x
const int maxn = 105;
const double INF = 0x3e3e3e3e;
double d[maxn][maxn], c[maxn], u[maxn], sum[maxn];
int n, w;
double dp(int i, int x) {
if (!i) return d[i][x] = (x == 0 ? 0 : INF);
if (d[i][x] >= 0) return d[i][x];
d[i][x] = INF;
for (int y = i - 1; y < x; y++) {
double p = double(x) * (sum[x] - sum[y]);
d[i][x] = min(d[i][x], dp(i - 1, y) + p);
}
return d[i][x];
}
int main() {
int T;
scan(T);
while (T--) {
scan2(n, w);
for (int i = 1; i <= n; i++) scanf("%lf", &u[i]);
sort(u + 1, u + 1 + n, greater<double>());
sum[0] = 0;
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + u[i];
CLR(d, -1);
double tans = dp(w, n);
double ans = tans / sum[n];
printf("%.4f\n", ans);
}
return 0;
}