第六周Dp练习整理(离散化)

4.12
E
Problem Description
A project manager wants to determine the number of the workers needed in every month. He does know the minimal number of the workers needed in each month. When he hires or fires a worker, there will be some extra cost. Once a worker is hired, he will get the salary even if he is not working. The manager knows the costs of hiring a worker, firing a worker, and the salary of a worker. Then the manager will confront such a problem: how many workers he will hire or fire each month in order to keep the lowest total cost of the project.

Input
The input may contain several data sets. Each data set contains three lines. First line contains the months of the project planed to use which is no more than 12. The second line contains the cost of hiring a worker, the amount of the salary, the cost of firing a worker. The third line contains several numbers, which represent the minimal number of the workers needed each month. The input is terminated by line containing a single ‘0’.

Output
The output contains one line. The minimal total cost of the project.

Sample Input
3 4 5 6 10 9 11 0
Sample Output
199

题意:经理雇佣工人,给出雇佣和解雇工人要花的费用,输出经理保证完成几个月任务前提下花费的最少成本。

分析:找到子问题,因为最后是输出最少的总费用,所以状态dp表示费用,问题涉及到每个月工人个数的选择是去是留所以,其中一变量为工人的个数,则另一变量就表示第几月。简之,dp[i][j]表示第i个月雇佣j个工人的费用,也表示前i个月雇佣工人所花的最少费用。
需要注意j的取值,[a[i],max]
状态转移方程:
dp[i][j]=min(dp[i-1][k]+pd(k,j)+j*pay)

#include<iostream>
#include<algorithm>
using namespace std;
int a[15];
int dp[15][100000];
int n,in,pay,out;
int pd(int a,int b)
{
    if(a>b) return out*(a-b);
    return in*(b-a);
}

int main()
{
    while(cin>>n)
    {
        if(n==0) break;
        cin>>in>>pay>>out;
        for(int i=1; i<=n; i++)
            cin>>a[i];
        int maxx=0;
        for(int i=1; i<=n; i++)
            if(a[i]>maxx) maxx=a[i];
        for(int i=1; i<=n; i++)
        {
            for(int j=a[i]; j<=maxx; j++)
            {
                dp[i][j]=99999999;
                if(i==1) dp[i][j]=pd(0,j)+pay*j;
                else
                {
                    for(int k=a[i-1]; k<=maxx; k++)
                        dp[i][j]=min(dp[i][j],dp[i-1][k]+pd(k,j)+j*pay);
                }
            }
        }
        int minn=9999999;
        for(int i=a[n];i<=maxx;i++) 
        minn=min(dp[n][i],minn);
        cout << minn << endl;
    }
    return 0;
}

4.17

Y (Dp+离散化+严格递增与非严格递增的转化)

https://vjudge.net/contest/430905

离散化使用,数组过大,这里是会使二维数组过大,易超时,所以我们找到另外一个数组去存储。
给了长度为n的序列,排序使其成为严格递增序列,最后输出原序列与非严格递增序列对应相减绝对值的最小值,即花费最小值。

若严格递增序列,也可将其转化非严格递增序列用同样的方法即可。

#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long
#define mm 1e18
using namespace std;
ll a[3010],b[3010];
ll d[3010][3010],minn=mm;
int main()
{
    int n,c=0;
    cin >> n;
    for(int i=1;i<=n;i++)
    {
        cin >> a[i];
        a[i]-=i;//严格转变不严格解题
        b[i]=a[i];
    }
    sort(b+1,b+1+n);
    c=unique(b+1,b+1+n)-b-1;//优化
    for(int i=1;i<=n;i++)
    {
        d[i][0]=mm;//初始!
        for(int j=1;j<=c;j++)
        {
            d[i][j]=min(d[i][j-1],d[i-1][j]+abs(a[i]-b[j]));
        }
    }
    cout <<d[n][c] << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值