uvalive4731

题目大意:
给出数字的个数n以及要分成的组数w。
然后给出各个数字的概率,
求最小的数学期望。

思路:
DP。因为要求最小的数学期望所以概率大的应该摆在前面,所以要先排序一下。
dp[i][j]表示的是第i组前j个数字可以得到的最小的数学期望。

代码:

#include 
using namespace std;
#include 
#include 
#include 
const int INF = 0x3f3f3f3f;
const int maxn = 105;

int f[maxn][maxn];
int num[maxn],sum[maxn];
bool cmp(int a,int b) {
    return a > b;
}
int main() {

    int t;
    scanf("%d",&t);
    while(t--) {
        int n,w;
        scanf("%d %d",&n,&w);
        for(int i = 1; i <= n; i++)
            scanf("%d",&num[i]);
        sort(num + 1, num + 1 + n,cmp);

        sum[1] = num[1];
        for(int i = 2; i <= n ; i++)
            sum[i] = num[i] + sum[i - 1];

        for(int i = 1; i <= w; i++) {//组数
            for(int j = i ; j <= i + n -w; j++) {//取前j个数字 为什么<= i + n - w是因为至少要留下w - i个数字才可以让后面的组有数字,所以j只能取n - (w - i)即i + n - w
                if(i == 1) {//如果是第一组的话就直接算
                    f[i][j] = j * sum[j];
                    continue;
                }
                f[i][j] = INF;
                for(int k = i - 1; k < j ; k++) 
                    f[i][j] = min(f[i][j],f[i - 1][k] + j *(sum[j] - sum[k]));//求出不同划分中最小的那个

            }
        }
        //printf("%d\n",f[w][n]);
        double ans = f[w][n]/100.0;
        printf("%.4lf\n",ans);
    }
    return 0;
}

你可能感兴趣的:(DP,区间dp)