• HDU 1158(非常好的锻炼DP思维的题目,非常经典)


    题目链接:

    acm.hdu.edu.cn/showproblem.php?pid=1158

    Employment Planning

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 6020    Accepted Submission(s): 2609


    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
     
    Source
     
     
    题意:
    一家公式完成一个项目,需要n个月的时间,每个月至少雇佣a1...an个工人,解雇工人和雇佣工人都需要一定的费用,每个月还要给雇来的工人工资,问你最少的花费是多少(不用输出方案,只有输出最优解)
    分析:
    解雇和雇佣工人都需要一定的费用,现在就是要看每个月怎么对工人进行解雇和雇佣的操作可以使得花费最少,每个月雇佣的工人可以>=这个月必须雇佣的工人数目,具体拿样例分析
    3
    4 5 6
    10 9 11
    代表3个月份,雇佣工人耗费4,一个雇佣的工人每月工资5,解雇工人耗费6
    第一个月至少雇佣10个人,第二个月至少雇佣9个人,第三个月至少雇佣11个人
    做法:
    该3个月份中最大工人数目为11,最小工人数目为9
    第一个月我们可以雇佣10个工人,或者11个工人
    第二个月我们需要的工人底线是9个,如果该月雇佣9个(需要解雇x人,x由上一个月雇佣人数决定(上一个月人数减去9),如果该月雇佣10个人(需要解雇人数x,也由上一个月雇佣人数决定),如果该月雇佣11个人,那么现在我们可能还需要继续的雇佣工人,
    第三个月也依次类推,
    这样不同的雇佣策略导致我们的花费肯定不同,在这些方案在花费中找到最小的即可
     
    dp的关键在于明白:前面一个月雇佣多少个人使得这个月的花费最小
     dp[i][j] :代表在第i个月的时候,雇佣J个人的总费用(雇佣费+工资)
    dp[i][j]=dp[i-1][k](前面一个月雇佣k个人,可以使得前面的i个月(包括i)的花费最小)+这个月的费用
              =dp[i-1][k]+abs(j-k)*v+j*工资  v表示解雇或者雇佣的权值,由j,k相对大小决定
    注意点:
    1.要知道每月需要工人的max和min(保证每月雇佣人数在这个集合之间,[min,max]),这样每个月雇佣的人数不同,花费也不同,才可以求解最优解
    2.初始化 第一个月的时候需要手动初始化,拿样例说,dp[1][9]第一个月雇佣9个人的费用(雇佣费加工资).......................dp[1][11]第一个月雇佣11个人的费用(雇佣费加工资),需要手动初始化
    3.最有解是在dp[n][j]中找最小的,j属于[min,max]集合
     
    重点:前面一个月雇佣多少人使得前面月份加上这个月份的花费最小
     
    代码如下:
    #include<bits/stdc++.h>
    using namespace std;
    #define inf 9999999
    int dp[20][105];
    int a[20];
    int hire,salary,fire;
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            if(n==0)
                break;
            scanf("%d %d %d",&hire,&salary,&fire);
            int max_people=-inf,min_people=inf;
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                max_people=max(max_people,a[i]);
                min_people=min(min_people,a[i]);
            }
            //dp[i][j] 在第i个月的时候,雇佣j个人的总费用(雇佣费+工资)
    
            //dp初始化
            memset(dp,0x3f,sizeof(dp));//无穷大
            for(int j=min_people; j<=max_people; j++)
            {
                dp[1][j]=hire*j+salary*j;
            }
    
            for(int i=2; i<=n; i++)
            {
                for(int j=a[i]; j<=max_people; j++)
                {
                    int t=inf;
                    for(int k=a[i-1]; k<=max_people; k++)
                    {
                        int v=hire;
                        if(k-j>0)//解雇
                        {
                            v=fire;
                        }
                        int x=dp[i-1][k]+abs(k-j)*v+j*salary;
                        t=min(t,x);
                    }
                    dp[i][j]=t;
                }
            }
            int t=inf;
            for(int j=1; j<=max_people; j++)
            {
                t=min(t,dp[n][j]);
            }
            printf("%d
    ",t);
        }
    }

    ojbk,溜了溜了,吃饭去

     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    史上最简洁的handler原理解释
    handler解惑
    Http中get和post的区别
    使用软引用缓存Bitmap
    Request头和Response头
    DNS编程实验--域名与IP的相互转换
    CString与string
    C++ string占多少个字节测试
    java中类的继承性和多态性实例
    java寻找html文件中的标签
  • 原文地址:https://www.cnblogs.com/yinbiao/p/9156962.html
Copyright © 2020-2023  润新知