题目描述
一家软件开发公司有两个项目,并且这两个项目都由相同数量的m个子项目组成,对于同一个项目,每个子项目都是相互独立且工作量相当的。由于时效性,两个项目必须同时被完成,如果其中一个完成的早了,那么这两个项目都会无效。
特别提醒:原文如此,题目实际意义是最晚的时间,并不是两个大项目必须要同时做完。比如项目1用16,项目2用18,则时间为18.
这家公司有n名程序员分配给这两个项目,每个子项目必须由一名程序员一次完成,多名程序员可以同时做同一个项目中的不同子项目。
求公司完成两个项目的最少时间。
输入
第一行两个正整数n,m(1<=n<=100,1<=m<=100)。
接下来n行,每行包含两个整数,x和y。分别表示每个程序员完成第一个项目的子程序的时间,和完成第二个项目子程序的时间。每个子程序耗时也不超过100。
输出
包含一个整数,表示两个项目同时完成的时间。
样例输入
3 20
1 1
2 4
1 6
样例输出
18
提示
【样例解释】
第一个人做18个2项目,耗时18;第二个人做2个1项目,2个2项目耗时12;第三个人做18个1项目,耗时18。
【数据范围】
对于30%的数据,n<=30.
对于60%的数据,n<=60.
Solution
一开始被题意误导了很久,如果题面没歧义的话,我们其实很容易得到一个dp
f[i][x][y]表示前i个人,项目1做了x个,项目2做了y个的最少时间
这样是
n∗m4
其实我们可以发现,不必去求时间,我们可以枚举时间,来验证能否满足,那么二分就呼之欲出了
最后的优化就是不必把项目2当做第三维,我们可以调整dp数组含义如下
f[i][x]表示前i个人项目1做了x个时,项目2已完成个数的最大值
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
int a[105],b[105],f[105][105];
int erfen(int l,int r)
{
if(l>r) return l;
int mid=(l+r)/2;
for(int i=0;i<=n;i++)
{
for(int j=1;j<=m;j++) f[i][j]=-1e9;
f[i][0]=0;
}
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=j;k++)
if(k*a[i]<=mid) f[i][j]=max(f[i][j],f[i-1][j-k]+(mid-k*a[i])/b[i]);
if(f[n][m]>=m) return erfen(l,mid-1); else return erfen(mid+1,r);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
cout<<erfen(1,10000);
return 0;
}