hdu 4412 Sky Soldiers (区间dp 单调性)

Sky Soldiers

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 556    Accepted Submission(s): 179

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.

This mission plans to place m provisions for the soldiers on the line for landing. These soldiers will be informed the direction of the nearest provision point by a special device after landing, and then walk to the point. The manager of this mission is asking
you for help: to determine m points for provisions so that the expected sum of walking distance should be minimized. You can put provisions on any point of the landing 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.

The following k lines contain descriptions of landing parameters for the soldiers numbered from 1 to k. Each description consists of an integer L followed by L pairs of (x, p), which indicates that the probability of the soldier‘s landing on integer coordination
x is p. It is guaranteed that all the p values are positive real numbers, and the sum of p in a single line is exactly 1. The same x may appear more than once on the same line which you should simply add up all the probability p of the pairs with equal x.

The number of places on which all the soldiers could land is no more than 1000 and it can not be less than m.

The input ends with k=m=0.

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

题意:

n个跳伞者,落地后,每个跳伞者可能会落在若干个点上,落在每个点都有一个概率(所有人都会落在x轴上)。现在在x轴上建立m个大本营,每个跳伞者走到最近的大本营。确定大本营建立的地点使得所有跳伞者所走的路程的期望最小。

思路:(来源于:点击打开链接

联系到dp,dp[i][j]表示第i个大本营处理完前j个人的最小期望值,有dp[i][j]=dp[i-1][k]+cost[k+1][j]。那么主要的任务就是求cost[i][j]了,枚举起点,遍历结束点,同一个起点不同终点的中心点随着终点递增的,考虑中心点移一步会产生的影响,于是就能在O(n*n)处理出来了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 1005
#define MAXN 200005
#define INF 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
const double pi=acos(-1.0);
typedef long long ll;
using namespace std;

int n,m,cnt;
map<int,double>mp;
map<int,double>::iterator it;
double cost[maxn][maxn];
double dp[55][maxn],p[maxn];
int pos[maxn];

void init()
{
    int i,j,cur;
    cnt=0;
    for(it=mp.begin();it!=mp.end();it++)
    {
        cnt++;
        pos[cnt]=it->first;
        p[cnt]=it->second;
    }
    double lp,rp,suml,sumr,best;
    for(i=1;i<=cnt;i++)
    {
        cost[i][i]=0;
        suml=sumr=rp=0;
        lp=p[i];
        cur=i;
        for(j=i+1;j<=cnt;j++)
        {
            rp+=p[j];
            sumr+=p[j]*(pos[j]-pos[cur]);
            best=suml+sumr;
            while(cur<cnt&&best>suml+sumr+(pos[cur+1]-pos[cur])*(lp-rp)) // 中心点右移
            {
                suml+=(pos[cur+1]-pos[cur])*lp;
                sumr-=(pos[cur+1]-pos[cur])*rp;
                lp+=p[cur+1];
                rp-=p[cur+1];
                best=suml+sumr;
                cur++;
            }
            cost[i][j]=best;
            //printf("i:%d j:%d cur:%d best:%lf\n",i,j,cur,best);
        }
    }
}
void solve()
{
    int i,j,k;
    double d,sum=p[1];
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=cnt;j++)
        {
            dp[i][j]=INF;
        }
    }
    for(j=1;j<=cnt;j++)
    {
        dp[1][j]=cost[1][j];
    }
    double ans=INF;
    for(i=1;i<m;i++)
    {
        for(j=1;j<=cnt;j++)
        {
            for(k=j+1;k<=cnt;k++)
            {
                dp[i+1][k]=min(dp[i+1][k],dp[i][j]+cost[j+1][k]);
            }
        }
        ans=min(ans,dp[i][cnt]);
    }
    ans=min(ans,dp[m][cnt]);
    printf("%.2f\n",ans);
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break ;
        mp.clear();
        int num,x;
        double d;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num);
            for(j=1;j<=num;j++)
            {
                scanf("%d%lf",&x,&d);
                mp[x]+=d;
            }
        }
        init();
        solve();
    }
    return 0;
}
/*
2 1
2 0 0.5 1 0.5
2 1 0.1 3 0.9
0 0
*/
时间: 2024-08-08 17:21:33

hdu 4412 Sky Soldiers (区间dp 单调性)的相关文章

hdu 4412 Sky Soldiers(区间DP)

Sky Soldiers Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 559    Accepted Submission(s): 181 Problem Description An airplane carried k soldiers with parachute is plan to let these soldiers j

HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)

题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. 简单的区间dp,哎,以为很神奇的东西,其实也是dp,只是参数改为区间,没做过此类型的题,想不到用dp,以后就 知道了,若已经知道[0,i],推[0,i+1], 显然还要从i+1 处往回找,dp方程也简单: dp[j][i]=(dp[j+1][i]+dp[j][i-1]+10007-dp[j+1][

HDU 5396 Expression (区间DP)

链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5396 设d[i][j] 代表i~j的答案.区间DP枚举(i, j)区间的断点,如果断点处的操作符是'*',那么该区间的答案可以直接加上d[i][k] *  d[k+1][j],因为乘法分配律可以保证所有的答案都会乘起来.如果是加法,需要加的 就是 左边的答案 乘 右边操作数的阶乘 加上 右边的答案乘左边操作数的阶乘,最后要确定左边操作和右边操作的顺序 因为每个答案里是统计了该区间所有的阶乘情况,因此

hdu 6049---Sdjpx Is Happy(区间DP+枚举)

题目链接 Problem Description Sdjpx is a powful man,he controls a big country.There are n soldiers numbered 1~n(1<=n<=3000).But there is a big problem for him.He wants soldiers sorted in increasing order.He find a way to sort,but there three rules to obe

hdu 5693 &amp;&amp; LightOj 1422 区间DP

hdu 5693 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5693 等差数列当划分细了后只用比较2个或者3个数就可以了,因为大于3的数都可以由2和3组合成. 区间DP,用dp[i][j]表示在i到j之间可以删除的最大数,枚举区间长度,再考虑区间两端是否满足等差数列(这是考虑两个数的),再i到j之间枚举k,分别判断左端点右端点和k是否构成等差数列(还是考虑两个数的),判断左端点,k,右端点是否构成等差数列(这是老驴三个数的) 1 #include

hdu 4597 Play Game 区间dp

Play Game Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4597 Description Alice and Bob are playing a game. There are two piles of cards. There are N cards in each pile, and each card has a score. They take tur

hdu 5181 numbers——思路+区间DP

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5181 题解:https://www.cnblogs.com/Miracevin/p/10960717.html 原来卡特兰数的这个问题还能区间DP…… XO #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; int rdn() { in

hdu 4570 Multi-bit Trie 区间DP入门

Multi-bit Trie 题意:将长度为n(n <= 64)的序列分成若干段,每段的数字个数不超过20,且每段的内存定义为段首的值乘以2^(段的长度):问这段序列总的内存最小为多少? 思路:区间的最值,区间DP; 枚举长度,在初始化时,将长度和20比较,小于20看成是一段,大于20时,因为不能压缩,直接全部分割就是了:之后枚举区间内部的所有值,这是并不需要考虑将这个区间一分为二后各自的长度是否大于20,因为在子结构中已经计算好了:直接去最优解即可: #include<iostream>

!HDU 4283 屌丝联谊会-区间dp

题意:一群屌丝排队参加联谊,每个人都有屌丝值,如果他是第k个进场的,那么他的愤怒值就是(K-1)*Di,主办方想使所有屌丝的愤怒值总和最小,就用一个黑屋子来改变屌丝的进场顺序,黑屋子实际上是一个栈,先进后出.现在要求用这个栈能得到的最小的愤怒值总和是多少. 分析: 难点在于你不知道用了多少次黑屋子.用在哪些人身上以及每次各自进黑屋子的人数.很容易知道每个决策都会影响最终结果,那么我们就想用dp来做.问题是哪种dp,本题实际上就是在区间上求最优解,所以用区间dp.区间dp就是每次把一个区间分成两个