UVALive 4731 Cellular Network 【dp】

题意:n个数分成w组,每组的值为到现在这组为止元素个数乘以该组概率之和,求出最小的和。

分析:贪心思想可知,概率越大的放越早越好,因为前面的系数小,所以我们把所有数排个序。但是每个组的系数是有加入的元素个数决定的。

用dp解决,设dp[i][j]表示前i个数分成j组能获得的最小值。

dp[i][j]=min(dp[i][j],dp[i-k][j-1]+i*(sum[i]-sum[i-k]));

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 105
#define Mm 200
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[Mn],sum[Mn];
int dp[Mn][Mn];
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",&a[i]);
        sort(a+1,a+1+n);
        CLR(dp,0x3f);
        sum[0]=0;
        dp[0][0]=0;
        for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[n-i+1];
        for(int i=1;i<=n;i++) {
            for(int j=1;j<=w;j++) {
                for(int k=1;k<=i;k++) {
                    dp[i][j]=min(dp[i][j],dp[i-k][j-1]+i*(sum[i]-sum[i-k]));
                }
            }
        }
        printf("%.4f\n",dp[n][w]*1.0/sum[n]);
    }
    return 0;
}


你可能感兴趣的:(UVALive 4731 Cellular Network 【dp】)