题意: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; }