Employment Planning

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

解题思路:

这个题我竟然被卡死在了输出上。我在最后一个月对应的每一种人数完成状态转移后就进行了比较,来更新最小值,然后就不停的WA,反而是把比较的过程放在全部DP完成之后再更新最小值AC了。。。。太鸡儿玄学了吧,这两种方式理论上没有区别啊,调试的时候对应的状态输出也完全一样啊。。。最后也没弄明白。。。
子问题就是当前月是该解雇一批人还是应该雇佣一批人,这取决于上个月“留”有多少人(并不是上个月需要多少人),如果上个月人数比这个月需要的人多,就解雇双方的差值,否则就雇佣。状态转移方程分两种情况,即是解雇还是雇佣。
AC代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
const int inf = 0x3fffffff;
using namespace std;
int dp[13][10010];
int main()
{
  int n;
  while(cin>>n&&n)
  {
    int month[13]={0},hire,salary,fire,ma=0;
    cin>>hire>>salary>>fire;
    int m1=inf;
    for(int i=1;i<=n;i++)
    {
      cin>>month[i];
      if(month[i]>ma)ma=month[i];
    }
    for(int i=month[1];i<=ma;i++)dp[1][i]=(salary+hire)*i;
    for(int i=2;i<=n;i++)
    {
      for(int j=month[i];j<=ma;j++)
      {
        int mi=inf;
        for(int k=month[i-1];k<=ma;k++)
        {
          if(j>k)mi=min(mi,hire*(j-k)+salary*j+dp[i-1][k]);
          else mi=min(mi,fire*(k-j)+salary*j+dp[i-1][k]);
        }
        dp[i][j]=mi;
      }
    }
    for(int i=month[n];i<=ma;i++)
      if(dp[n][i]<m1)m1=dp[n][i];
    cout<<m1<<endl;
    memset(dp,0,sizeof(dp));
  }
  return 0;
}

WA代码如下,唯一不同就是更新最小值的方式(我觉得理论上一样啊,求大神解释)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
const int inf = 0x3fffffff;
using namespace std;
int dp[13][10010];
int main()
{
  int n;
  while(cin>>n&&n)
  {
    int month[13]={0},hire,salary,fire,ma=0;
    cin>>hire>>salary>>fire;
    int m1=inf;
    for(int i=1;i<=n;i++)
    {
      cin>>month[i];
      if(month[i]>ma)ma=month[i];
    }
    for(int i=month[1];i<=ma;i++)dp[1][i]=(salary+hire)*i;
    for(int i=2;i<=n;i++)
    {
      for(int j=month[i];j<=ma;j++)
      {
        int mi=inf;
        for(int k=month[i-1];k<=ma;k++)
        {
          if(j>k)mi=min(mi,hire*(j-k)+salary*j+dp[i-1][k]);
          else mi=min(mi,fire*(k-j)+salary*j+dp[i-1][k]);
        }
        dp[i][j]=mi;
        if(i==n&&dp[i][j]<m1)m1=dp[i][j];
      }
    }
  /*  for(int i=month[n];i<=ma;i++)
      if(dp[n][i]<m1)m1=dp[n][i];*/
    cout<<m1<<endl;
    memset(dp,0,sizeof(dp));
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/A7_RIPPER/article/details/81272952