2017.2.11【初中部 GDKOI】模拟赛B组 T2:软件公司
**【NOIP2013模拟11.6B组】软件公司(company) **
Description
一家软件开发公司有两个项目,并且这两个项目都由相同数量的m个子项目组成,对于同一个项目,每个子项目都是相互独立且工作量相当的,并且一个项目必须在m个子项目全部完成后才算整个项目完成。
这家公司有n名程序员分配给这两个项目,每个子项目必须由一名程序员一次完成,多名程序员可以同时做同一个项目中的不同子项目。
求最小的时间T使得公司能在T时间内完成两个项目。
Input
第一行两个正整数n,m(1<=n<=100,1<=m<=100)。
接下来n行,每行包含两个整数,x和y。分别表示每个程序员完成第一个项目的子程序的时间,和完成第二个项目子程序的时间。每个子程序耗时也不超过100。
Output
输出最小的时间T。
Sample Input
3 20
1 1
2 4
1 6
Sample Output
18
【样例解释】
第一个人做18个2项目,耗时18;第二个人做2个1项目,2个2项目耗时12;第三个人做18个1项目,耗时18。
题解:本题还是挺简单的,但是要灵活去想动态规划和二分查找,还要灵活应用。当然,被你发现了,本题正解就是二分查找用动态规划优化。(好像很深奥)但是,60%和30%也很值得一提!
30%:可以用一个二分查找来查找答案,然后再判断一下成不成立就30分到手啦!!
60%:当然是用DP啦。这个dp我是用一种神奇的方法,f[i,x,y]表示,第i个人,第一批项目已完成x个子项目,第二批项目已完成y个子项目的最短时间。dp方程自己想想,当然,也有第二种方法(不一定是60分,但数据这么水,我也无法确定)。第二种方法:f[i,j]表示,当选到第i个人,第一批货物已完成j个子项目,还可以做多少个二项目。这种方法更简单,当然更快,100分就用到了这种方法。
方法1伪代码:
for i:=1 to n do
begin
for a:=0 to m do
begin
for b:=0 to m do
begin
for o:=0 to a do
begin
for p:=0 to b do
begin
f[i,a,b]:=min(f[i,a,b],max(f[i-1,a-o,b-p],o*x[i]+p*y[i]));
end;
end;
end;
end;
end;
100%:在二分里面的判断过程,用dp来做就非常快啦,然后100分就到手啦~~~
标程:
var
i,j,k,l,n,m,a,b,o,p:longint;
f:array[0..100,0..100,0..100] of longint;
x,y:array[1..100] of longint;
function max(x,y:longint):longint;
begin if x>y then exit(x); exit(y); end;
function min(x,y:longint):longint;
begin if x<y then exit(x); exit(y); end;
begin
assign(input,'company.in');reset(input);
assign(output,'company.out');rewrite(output);
readln(n,m);
for i:=1 to n do
begin
readln(x[i],y[i]);
end;
fillchar(f,sizeof(f),127);
f[0,0,0]:=0;
qs(1,n);
for i:=1 to n do
begin
for a:=0 to m do
begin
for b:=0 to m do
begin
for o:=0 to a do
begin
for p:=0 to b do
begin
f[i,a,b]:=min(f[i,a,b],max(f[i-1,a-o,b-p],o*x[i]+p*y[i]));
end;
end;
end;
end;
end;
writeln(f[n,m,m]);
end.
动态规划还是要会呀,当然,也要放开算法的拘束,搞搞别的东东,说不定就是正解了!!!