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