Sky SoldiersTime Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 926 Accepted Submission(s): 350 Problem Description An airplane carried k soldiers with parachute is plan to let these soldiers jump off the plane along a straight air route. The landing point of these soldiers is undetermined because of various weather conditions. However, the statisticians of the army can analysis the probability of landing in a certain place through landing history records. To make it simple, the statistician suggests that these sky soldiers will land on finite discrete points of a straight line.
Input There are multiple test cases. For each case, the first line contains two integers k and m (1 ≤ k ≤ 1,000, 1 ≤ m ≤ 50), which represent the number of sky soldiers and the number of positions to place provisions separately.
Output For each test case, output a line containing only one real number which indicates the minimum expected sum of distance these soldiers will move and should be rounded to two digits after the decimal point.
Sample Input 2 1 2 0 0.5 1 0.5 2 1 0.1 3 0.9 0 0
Sample Output 2.30
Source 2012 ACM/ICPC Asia Regional Hangzhou Online
Recommend liuyiding | We have carefully selected several similar problems for you: 6318 6317 6316 6315 6314
|
题解:
题解的转移有点迷,但仔细一想的确是对的.
题意:
n个伞兵,落地后,每个伞兵可能会落在若干个点上点都在x轴上,落在每个点都有一个概率。现在在x轴上建立m个基地,每个伞兵走到最近的基地。确定基地建立的地点使得所有伞兵所走的路程总和的期望最小。
思路:
乍一看像期望dp。仔细思考后可以发现这是一个区间DP。假设一个伞兵落在x点。那么他走的路程的期望为p1*|x1-x|+p2*|x2-x|....*pm*|xm-x|。所以我们可以把n个伞兵等价成一个伞兵。然后它到一个点的概率为所有伞兵到那点的概率总和。那现在就可以写出状态了。dp[i][j]表示在前i个位置建j个基地。该等效伞兵走的路程的最小期望。那么这题就类似poj 1160 Post Office那题了。转移方程为dp[i][j]=dp[k][j-1]+cost[k+1][i]。k<i。cost[i][j]表示在i,j之间建一个基地且该基地负责集合[i,j]上的伞兵。所走距离的期望。现在重点怎么快速算cost[i][j]了。考虑我们在算cost[j][i]的时候。随着j的减小基地的最优位置cur要么前移要么不变。所以我们就可以在O(n^2)的时间复杂度下算出了。
这个dp可以这样写因为就算你这次转移的不是最优的情况即区间k--j--i,j--i区间里的某些转移到k--j这个区间更优,但你下次还是会枚举到某个恰好的区间使得每个点转移到的区间距离最短(因为枚举了所有区间)。
代码:
#include<bits/stdc++.h>
using namespace std;
map<int,double> mp;
struct aaa{
int x;
double y;
}a[2001];
int n,m,t,dis,now,i,j,k;
double cl,cr,ls,rs,sum,t1,f[2001][55],cost[2001][2001];
int main(){
while(1){
mp.clear();
scanf("%d%d",&n,&m);
if(!n&&!m)return 0;
for(i=1;i<=n;i++){
scanf("%d",&k);
for(j=1;j<=k;j++){
scanf("%d%lf",&t,&t1);
mp[t]+=t1;
}
}
n=0;
for(map<int,double>::iterator it=mp.begin();it!=mp.end();it++){
a[++n].x=it->first;
a[n].y=it->second;
}
for(i=n;i;i--){
cost[i][i]=0;
now=i;
rs=a[i].y;
cl=cr=ls=0;
for(j=i-1;j;j--){
dis=a[now].x-a[j].x;
cl+=dis*a[j].y;
ls+=a[j].y;
sum=cl+cr;
while(now>1&&ls>rs){
dis=a[now].x-a[now-1].x;
cl-=ls*dis;
cr+=rs*dis;
now--;
rs+=a[now].y;
ls-=a[now].y;
sum=cl+cr;
}
cost[j][i]=sum;
//printf("%d %d %.2lf\n",j,i,cost[j][i]);
}
}
for(i=0;i<=m;i++)f[i][i]=0;
for(i=1;i<=n;i++)f[i][0]=1e15;
for(j=1;j<=m;j++)
for(i=j;i<=n;i++){
sum=1e15;
for(k=j-1;k<i;k++)
sum=min(sum,f[k][j-1]+cost[k+1][i]);
f[i][j]=sum;
}
printf("%.2lf\n",f[n][m]);
}
}