NOIP模拟试题 软件开发(二分DP)
2016-08-08 10:41
351 查看
【题目描述】
一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。写一个程序,求出公司最早能在什么时候交付软件。
【输入】
输入文件第一行包含两个由空格隔开的整数n和m,其中1≤n≤100,1≤m≤100。接下来的n行每两个用空格隔开的整数d1和d2,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中
l≤d1,d2≤100。
【输出】
输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。
【样例】
Software.in
3 20
1 1
2 4
1 6
software.out
18
【样例】
最快的方案是第一个技术人员完成第二个软件的18个模块,用时18天,第三个技术人员完成第一个软件的18个模块,用时18天,其余的模块由第二个技术人员完成,用时12天,做完所有模块需要18天。如果第一个技术人员完成第二个软件的17个模块,第三个技术人员完成第一个软件的17个模块,其余的模块由第二个技术人员完成,需要用时18天,做完所有模块仍然需要18天,所以少于18天不可能做完所有模块。
解题思路:
首先看到这题我想到的是dp,但是我没写出来,(后来听说有同学写了DP,5层循环,超时了TAT)于是我想到了二分答案,但是对于答案的验证我还是采取了暴力的算法,但是测试数据太水,竟然没卡掉时间,后来我看到标准的题解说这题应该用二分加DP,我觉得这个思路不错,所以写这篇博客和大家分享一下。
我们首先二分查找一个答案,再进行DP,我们设一个数组F[i][j]表示前i个人生产j个A工件最多能生产多少个B工件,再加上二分答案mid,我们枚举到第i个人时就可以在前i-1个人中枚举一个k,意思就是让第i个人生产k个A工件,剩下的mid-k*A[i]时间就用来生产B工件,于是我们有动态转移方程:
[m]即可。但是有一个细节,就是初值的问题,如果我们把初值设成0的话,会错!!!建议自己试一下,样例都过不去,为什么呢,我们可以这样分析。我们每个状态表示的是前i个人在mid时间内生产了j个A物品后最多还能生产多少个B物品,如果我们要是把初值设成零的话就相当于无论我前i个人生产多少个A物品,都可以生产零个B物品,这样就会引入很多个根本不可能存在的状态,比如F[1][100],而且这些状态还可能去更新其他状态。那我们怎么解决呢,有一个很简单的办法就是将初值变为-INF,这样就可以避免无关状态对答案的影响了>_<。
一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成。一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块。写一个程序,求出公司最早能在什么时候交付软件。
【输入】
输入文件第一行包含两个由空格隔开的整数n和m,其中1≤n≤100,1≤m≤100。接下来的n行每两个用空格隔开的整数d1和d2,d1表示该技术人员完成第一个软件中的一个模块所需的天数,d2表示该技术人员完成第二个软件中的一个模块所需的天数,其中
l≤d1,d2≤100。
【输出】
输出文件仅有一行包含一个整数d,表示公司最早能于d天后交付软件。
【样例】
Software.in
3 20
1 1
2 4
1 6
software.out
18
【样例】
最快的方案是第一个技术人员完成第二个软件的18个模块,用时18天,第三个技术人员完成第一个软件的18个模块,用时18天,其余的模块由第二个技术人员完成,用时12天,做完所有模块需要18天。如果第一个技术人员完成第二个软件的17个模块,第三个技术人员完成第一个软件的17个模块,其余的模块由第二个技术人员完成,需要用时18天,做完所有模块仍然需要18天,所以少于18天不可能做完所有模块。
解题思路:
首先看到这题我想到的是dp,但是我没写出来,(后来听说有同学写了DP,5层循环,超时了TAT)于是我想到了二分答案,但是对于答案的验证我还是采取了暴力的算法,但是测试数据太水,竟然没卡掉时间,后来我看到标准的题解说这题应该用二分加DP,我觉得这个思路不错,所以写这篇博客和大家分享一下。
我们首先二分查找一个答案,再进行DP,我们设一个数组F[i][j]表示前i个人生产j个A工件最多能生产多少个B工件,再加上二分答案mid,我们枚举到第i个人时就可以在前i-1个人中枚举一个k,意思就是让第i个人生产k个A工件,剩下的mid-k*A[i]时间就用来生产B工件,于是我们有动态转移方程:
f[i][j]=max(f[i-1][j-k]+(mid-v1[i]*k)/v2[i],f[i][j])
然后我们用递推的方法算出F[m]即可。但是有一个细节,就是初值的问题,如果我们把初值设成0的话,会错!!!建议自己试一下,样例都过不去,为什么呢,我们可以这样分析。我们每个状态表示的是前i个人在mid时间内生产了j个A物品后最多还能生产多少个B物品,如果我们要是把初值设成零的话就相当于无论我前i个人生产多少个A物品,都可以生产零个B物品,这样就会引入很多个根本不可能存在的状态,比如F[1][100],而且这些状态还可能去更新其他状态。那我们怎么解决呢,有一个很简单的办法就是将初值变为-INF,这样就可以避免无关状态对答案的影响了>_<。
#include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<iostream> #include<iomanip> #include<cmath> #include<ctime> #include<algorithm> using namespace std; int n,m; int v1[101]; int v2[101]; int f[101][101]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&v1[i],&v2[i]); int l=1,r=20000; int ans; while(l<=r) { int mid=(l+r)>>1; memset(f,-0x7f,sizeof(f)); f[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=mid/v1[i];k++) { if(k>j) break; f[i][j]=max(f[i-1][j-k]+((mid-(v1[i]*k))/v2[i]),f[i][j]); } if(f [m]>=m) { ans=mid; r=mid-1; } else l=mid+1; } cout<<ans; return 0; }
相关文章推荐
- 【三校联考试题】软件开发 二分+dp
- JZOJ 1217 软件开发 二分+DP
- 软件开发工具试题
- 软件开发模式之工厂模式模拟魔兽英雄创建(Darren)
- 腾讯2016春招实习生(软件开发)笔试模拟卷
- 京东价格监控软件开发技术探讨三:使用C#模拟京东登录
- [NOIP 模拟]疫情延迟 二分+Spfa
- NOIP2011-普及组复赛模拟试题-第一题-NBA总冠军
- 2016年4月CCF计算机软件能力认证模拟试题代码参考
- NOIP2010-普及组复赛模拟试题-第一题-手机
- (NOIP2015)复赛模拟试题 vijos1165 火烧赤壁
- 软件开发应试人员考试试题(Java)
- 网络实用软件模拟试题
- PVTsim.V20 多用途PVT模拟软件(油气勘探开发)完整全功能版本
- 2013蓝桥杯全国软件大赛C++模拟试题-画表格-解答 .
- NOIP2011-普及组复赛模拟试题-第二题-买票
- 冲刺NOIP2011 模拟试题(七)
- 2013蓝桥杯全国软件大赛C++模拟试题-四方定理-解答
- 华为2011软件开发校园测试机试题--身份证号码合法性判断
- 中大型软件系统开发要点1-需求整理与系统模拟发现必需需求