hdu1158【DP】

题意:

第一行项目数;

第二行每个工人的Hire Salary Fire money

第三行每个项目需要的人的数量;

工人在hire/fire的时候要付出额外的钱,如果已经hire了还没有fire就一直会付salary求一个最小开支。

思路:

这题因为感觉就是DP,所以也没想贪心。。

H:hire的钱

S:salary

F:firep[]代表项目人数;

首先可以看出:

①:p[i-1]<p[i] :要再雇几个人,前一状态+H*(p[i]-p[i-1])+S*p[i]

②:p[i-1]==p[i] :直接就是 前一状态+S*p[i]

③:p[i-1]>p[i] :要先去几个人,前一状态+F*(p[i]-p[i-1])+S*p[i]

用dp[i][j]代表前i个项目的j个人的消费;

从前一状态到后一状态的改变:我们可以想到最多最多雇的人不会超过期间最多的人;

所以对于每次状态的更新都要更新到最多人次,而每次人次的下界,并不是最小,因为对于第i个项目你最小要拿p[i]个人,所以每次状态的更新是从p[i]到会出现的最多人次;

然后转移过来的值,就是在之前的状态经过转换后的一个最小值,而前一状态有:dp[i-1][j],p[i-1]<=j<=tmax(某项目最多人)

那么初始化,状态转移就不难了~

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=12+10;
const int INF=0x3f3f3f3f;

int p[N];
int dp[N][1010];
int H;
int S;
int F;
int n;

int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        scanf("%d%d%d",&H,&S,&F);
        scanf("%d",&p[1]);
        int tmax=p[1];
        for(int i=2;i<=n;i++)
        {
            scanf("%d",&p[i]);
            tmax=max(p[i],tmax);
        }
        memset(dp,0,sizeof(dp));

        for(int i=p[1];i<=tmax;i++)
            dp[1][i]=i*S+i*H;

        int temp;
        for(int i=2;i<=n;i++)
        {
            for(int j=p[i];j<=tmax;j++)//对于第i次的更新;
            {
                temp=INF;
                for(int k=p[i-1];k<=tmax;k++)//从前一状态拿一个最小值;
                    if(temp>dp[i-1][k]+(j>=k?(j*S+(j-k)*H):(j*S+(k-j)*F)))
                        temp=dp[i-1][k]+(j>=k?(j*S+(j-k)*H):(j*S+(k-j)*F));
                dp[i][j]=temp;
            }
        }
        int ans=dp[n][p[n]];
        for(int i=p[n]+1;i<=tmax;i++)
            ans=min(ans,dp[n][i]);
        printf("%d\n",ans);
    }
    return 0;
}



posted @ 2016-09-18 23:33  see_you_later  阅读(125)  评论(0编辑  收藏  举报