一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。写一个程序,求出公司最早能在什么时候交付软件。
输入文件第一行包含两个由空格隔开的整数n和m,其中1<=n<=100,1<=m<=100,接下来的n行每行包含两个用空格隔开的整数d1和d2,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中1<= d1,d2<=100。
输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。
3 20
1 1
2 4
1 6
18
【样例解释】
最快的方案是第一个技术人员完成第二个软件的18个模块,用时18天,第三个技术人员完成第一个软件的18个模块,用时18天,其余的模块由第二个技术人员完成,用时12天,做完所有模块需要18天。如果第一个技术人员完成第二个软件的17个模块,第三个技术人员完成第一个软件的17个模块,其余的模块由第二个技术人员完成,需要用时18天,做完所有模块仍然需要18天,所以少于18天不可能做完所有模块。
正解:二分+DP。
我们二分答案,设答案为mid, f[i][j] 表示前i个人完成了第一个软件的j个模块,此时还可以完成第二个软件的最多模块数。设第i个人要完成k个模块,那么前i-1个人完成了j-k个模块。完成第二个软件的模块数为 (mid−k∗d1i)/d2i .
那么方程出来了:
#include
#include
#include
#include
#include
#define N 110
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int f[N][N],d[N][2],i,j,k,l,mid,r,n,m,t;
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d%d",&d[i][0],&d[i][1]);
l=0;
r=10000;
while (l
{
mid=(l+r)/2;
fo(i,0,n) fo(j,0,m) f[i][j]=-2147483647;
f[0][0]=0;
fo(i,1,n)
fo(j,0,m)
fo(k,0,min(j,mid/d[i][0]))
f[i][j]=max(f[i][j],f[i-1][j-k]+(mid-d[i][0]*k)/d[i][1]);
if (f[n][m]>=m) r=mid;else l=mid+1;
}
printf("%d",l);
}
——2016.7.11