题意: 存在一个蜂窝网络,有n个部分,有一部手机存在着n个部分中的某一个,给定每个部分的存在概率,现在要将这n个部分分成w块,每一块内的部分同时访问。让你完成划分并输出找到手机的最小访问块数期望。
分析: 显然先访问大概率的部分,使期望最小。先将n部分按概率从大到小排序,每次划分块时选择连续的一段。dp[i][j]为前i部分划分成j块的最小期望,有如下转移:
dp[i][j] = min(dp[i][j], dp[k][j-1] + 第k+1块到第i块有手机的概率*i块)。O(n^3)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int T,n,w,u[110];
int dp[110][110],p[110],s[110];
bool cmp(int a,int b) {
return a>b;
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&w);
int sum=0;
for(int i=1;i<=n;i++) {
scanf("%d",&p[i]);
sum+=p[i];
}
sort(p+1,p+1+n,cmp);
for(int i=1;i<=n;i++)
s[i]=s[i-1]+p[i];
memset(dp,inf,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=w;j++) {
for(int k=j-1;k<i;k++) {
dp[i][j]=min(dp[i][j],dp[k][j-1]+i*(s[i]-s[k]));
}
}
}
printf("%.4f\n",1.0*dp[n][w]/sum);
}
return 0;
}