HDU 4412 Sky Soldiers(区间DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4412

 

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

 

思路:题目最后等价于若干个点,每个点有一个权值。设dp[i][j]表示前i个点建立j个大本营的最小代价,cost[i][j]表示在[i,j]上建立一个大本营的代价。则dp[i][j]=min(dp[k][j-1]+cost[k+1][i])(0<=k<i)。对于计算cost[i][j],可以知道,我是从后向前算的,每次建立大本营的地点肯定是保持不动或者向前挪,所以它是单调的。。。

 

#include <iostream>

#include <cstdio>

#include <cstring>

#include <map>

#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;





struct Node

{

    double pos,p;

};



const double INF=1000000000000;

const int MAX=1005;

const int MAXN=55;

double dp[MAX][MAXN],cost[MAX][MAX];

Node a[MAX];

int n,m;

map<int,double> hash;

map<int,double>::iterator it;





void init()

{

    int i,j,cur;

    double Lp,Rp,sumL,sumR,temp;

    for(i=n;i>=1;i--)

    {

        cur=i;

        cost[i][i]=0;

        sumL=sumR=0;

        Lp=0;

        Rp=a[cur].p;

        for(j=i-1;j>=1;j--)

        {

            Lp+=a[j].p;

            sumL+=(a[cur].pos-a[j].pos)*a[j].p;

            temp=sumL+sumR;

            while(cur>1&&temp>sumL+sumR+(Rp-Lp)*(a[cur].pos-a[cur-1].pos))

            {

                sumL-=Lp*(a[cur].pos-a[cur-1].pos);

                sumR+=Rp*(a[cur].pos-a[cur-1].pos);

                cur--;

                Lp-=a[cur].p;

                Rp+=a[cur].p;

                temp=sumL+sumR;

            }

            cost[j][i]=temp;

        }

    }

}





void DP()

{

    int i,j,k;

    double _min;

    dp[1][1]=0;

    for(i=1;i<=n;i++) dp[i][0]=INF;

    for(i=1;i<=m;i++) dp[0][i]=0;

    for(i=2;i<=n;i++)

    {

        for(j=1;j<=m;j++)

        {

            _min=INF;

            for(k=0;k<i;k++) _min=min(_min,dp[k][j-1]+cost[k+1][i]);

            dp[i][j]=_min;

        }

    }

    printf("%.2lf\n",dp[n][m]);

}



int main()

{

    while(scanf("%d%d",&n,&m),n||m)

    {

        hash.clear();

        int i,k,x;

        double p;

        for(i=1;i<=n;i++)

        {

            scanf("%d",&k);

            while(k--)

            {

                scanf("%d%lf",&x,&p);

                hash[x]+=p;

            }

        }

        n=0;

        for(it=hash.begin();it!=hash.end();it++)

        {

            a[++n].pos=it->first;

            a[n].p=it->second;

        }

        init();

        DP();

    }

    return 0;

}

  

你可能感兴趣的:(HDU)