洛谷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;
}
posted @ 2020-03-01 10:37  Allen_Gun  阅读(96)  评论(1编辑  收藏  举报