题目:
题意:
有n个飞行员,每个飞行员都有c个落点和相应的概率,要建立m个补给站,使得n个飞行员到达补给站的期望值最小。
思路:
dp[i][j] 表示前i个落点建立j个补给站的最小期望值。
dp[i][j] = min(dp[k][j-1], cost[k][i] ) 。
cost[k][i] 表示区间(k,i)建立1个补给站供给此区间中的飞行员的期望值。
期望值 = (落点- 补给站)* 落点概率。
AC.
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const double inf = 1e8*1.0;
const int maxn = 1005;
map<int, double> mp;
double dp[maxn][80], cost[maxn][maxn];
struct node {
double x, p;
bool operator < (const node & A) const {
return x < A.x;
}
}num[maxn];
int main()
{
//freopen("in", "r", stdin);
int n, m;
while(~scanf("%d%d", &n, &m)) {
if(n == 0 && m == 0) break;
mp.clear();
for(int i = 0; i < n; ++i) {
int c, x;
double p;
scanf("%d", &c);
while(c--) {
scanf("%d %lf", &x, &p);
mp[x] += p;
}
}
int N = 1;
map<int, double>::iterator it;
for(it = mp.begin(); it != mp.end(); it++) {
num[N].x = it->first;
num[N++].p = it->second;
}
sort(num, num+N);
double fl, fr, pl, pr;
for(int i = N-1; i >= 1; --i) {
cost[i][i] = 0;
fl = fr = pl = pr = 0; // 期望 概率
pr = num[i].p;
int pos = i;
for(int j = i-1; j >= 1; --j) {
pl += num[j].p;
fl += num[j].p * (num[pos].x - num[j].x);
double temp = fl + fr;
while(temp > fl + fr + (pr - pl)*(num[pos].x - num[pos-1].x) && pos > 1) {
pos--;
fl -= pl*(num[pos+1].x - num[pos].x);
fr += pr*(num[pos+1].x - num[pos].x);
pl -= num[pos].p;
pr += num[pos].p;
temp = fl + fr;
}
cost[j][i] = temp;
//printf("pos = %d, (%d %d) %lf\n", pos+1, j, i, temp);
}
}
for(int i = 0; i < N; ++i) {
for(int j = 0; j <= m; ++j) dp[i][j] = inf;
}
dp[0][0] = 0;
for(int i = 1; i < N; ++i) {
for(int j = 1; j <= m; ++j) {
for(int k = i; k >= 1; --k) {
dp[i][j] = min(dp[i][j], dp[k-1][j-1] + cost[k][i]);
}
}
}
printf("%.2lf\n", dp[N-1][m]);
}
return 0;
}