洛谷1800 software

  1. 题意:某公司要开发两个软件,每个有m个模块,有n个技术人员,每个人开发不同软件的时间不同。
  2. 思路:属于求最大值最小问题,求两个任务完成的最大天数的最小值。而且答案是单调的,于是想到了二分答案,就得到了天数,所以需要判断能否行得通,这时就想到了DP(类完全背包)。用软件1做m个时 当前天数是否满足做m个软件2为判断依据。
  3. 方程含义:f[i][j]表示前i个人做j个软件1的模块时最多能做几个软件二的模块。

    4. 方程 :f[i][j]=max{f[i][j],f[i-1][k]+res/b[i]}//详见代码注释

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int N=110;
int n,m,a[N],b[N],l,r,mid,ans;
int f[N][N];

 bool dp(int num)
{
    memset(f,0,sizeof(f));
    f[0][0]=1;//初始化
    int i,j,k,res;
    for (i=1; i<=n; i++)
        for (j=0; j<=m; j++)
            for (k=j; k>=0; k--)//i-1个人做k个软件1模块,第i个人做j-k个
            {
                res=num-a[i]*(j-k);
                if (res<0) break;//判断第i个人能否做
                if (f[i-1][k]>0) f[i][j]=max(f[i][j],f[i-1][k]+res/b[i]);
            }
    
    if (f[n][m]>m) return true;
    return false;
}
 int main()
{
    int tmp=0;
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) 
    {
        scanf("%d%d",&a[i],&b[i]);
        if (a[i]+b[i]>tmp) tmp=a[i]+b[i];
    }
    r=tmp*m; l=1;
    while (l<=r)
    {
        mid=(l+r)/2;
        if (dp(mid)) {ans=mid; r=mid-1;}
        else l=mid+1;
    }//熟悉的二分
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lyxzhz/p/12388569.html