Poj 1973 Software Company(二分+并行DP)
题意:软件公司接了两个项目,来自同一个合同,要一起交付。该公司有n个程序猿来做这两个项目A和B,每个项目都被分为m个子项目,给定每个程序猿做一个A中的子项目需要的时间Xi秒,和做B中的子项目所需时间Yi秒,问最短需要多少时间可以完成这两项工程。
分析:显然同一时刻不同的工人可以一起工作,那么面临的问题也就是一个工作的分配,让某一时刻的某个工人干A还是干B,来使AB尽快都完成。刚始做的时候确实没有什么头绪,后来看了大牛们的解题报告,大多是二分时间判断再加上并行DP来解决这个问题。但是仔细分析的好像特别少,想我这种菜鸟真是看不懂。隔了两天,还是硬着头皮开始一步步分析他们的思路。
题解:二分时间呢,就是枚举时间,然后验证看看在这个时间内能否完成这两个项目。如果满足就用二分法进一步缩小范围,直到求得最精确地结果。这里也涉及到一个时间上限的问题,大家都知道,二分法在初始的时候有下限和上限两个值,下限很简单就设为1,上限要看题目的要求和测试数据的强弱了。这道题呢,上限设为30000就可以通过了,但是这里还是用动态获得上限为好。也就是根据输入数据求得上限,这个上限就是完成这两个项目的最长时间,那么我们可以求得所有程序猿中完成单个子项目的最大值Max,再乘以子项目的总数2m就是粗略的上限了。这里还可以优化,因为我们求得是最短的时间,肯定大大低于这个上限。如Max
/ (n+1) *2m。
还有一个就是DP的状态转移方程的确定了,首先,dp[ i ][ j ]表示前 i 个人在完成 j 个A子项目时最多能完成的B子项目的个数,最后只要判断dp[n][m]是否大于m就可以了,如果大于则满足要求,小于则不行。状态转移方程 为 dp[ i ][ j ] = max(dp[ i ][ j ], dp[ i-1 ][ j-k ] + (time-k * x[i] ) / y[i] );这个方程呢,之前一直没有理解,就是因为没有意识到这个是并行的运算。有句话说的好“时间对每个人都是公平的”,在这里也是一样,每个程序猿都有一个time,他可以选择在这个时间里做多少个A子项目和多少个B子项目,使得开发的进度满足公司的整体需求。这个转换方程求得是前
i 个人完成了j个A项目时,最多能完成的B子项目 。那么这就取决于第 i 个人的选择,如果第 i 个人完成 k 个A子项目,那么前 i-1 个人就应该完成了 j-k个A子项目。然而谁也不知道这个该死的第 i 个程序猿会做多少个A子项目啊,所以我们只能从0到m假设他做的A子项目,从中找到最短的时间。然后再告诉他应该做的确切的个数,服从公司的整体需求。这个问题用到了一个子循环可以解决。这里还可以有一个优化,在给定的时间下第 i 个程序猿可能做不了m个A子项目,最多只能做Time/a[i]个。
这里还有一个很重要的优化,就跟0-1背包的空间优化差不多。0-1背包时,把二维的dp数组用一维数组实现了,这里可以参照这种方法,用一维数组实现dp.
import java.util.Scanner; public class Main{
static int N =102;
static int[] a=new int[N];
static int[] b=new int[N];
static int[] dp=new int[N];
static int n,m;
static boolean judge(int time){
for(int i=0;i<N;i++){
dp[i]=-1;
}
dp[0]=0;
for(int i=0;i<n;i++){
for(int j=m;j>=0;j--)
if(dp[j] != -1){
for(int k=m;k>=0;k--){
if(a[i]*k <= time && j+k <= m)
dp[j+k]=Math.max(dp[j+k],dp[j]+(time-a[i]*k)/b[i]);
}
}
}
return dp[m] >= m;
} public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int cas=sc.nextInt();
while(cas--!=0){
n=sc.nextInt();
m=sc.nextInt();
int max_time=-1;
for(int i=0;i<n;i++){
a[i]=sc.nextInt();
b[i]=sc.nextInt();
max_time=Math.max(max_time,a[i]);
max_time=Math.max(max_time,b[i]);
}
max_time=max_time*m*2;
int left,right,mid;
int min_time=0;
left=1;
right=max_time;
while(left <= right){
mid=(left+right)>>1;
if(judge(mid)){
right=mid-1;
min_time=mid;
}
else
left=mid+1;
}
System.out.println(min_time);
}
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
Poj 1973 Software Company(二分+并行DP)的更多相关文章
- 二分+动态规划 POJ 1973 Software Company
Software Company Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 1112 Accepted: 482 D ...
- 任务调度分配题两道 POJ 1973 POJ 1180(斜率优化复习)
POJ 1973 这道题以前做过的.今儿重做一次.由于每个程序员要么做A,要么做B,可以联想到0/1背包(谢谢N巨).这样,可以设状态 dp[i][j]为i个程序员做j个A项目同时,最多可做多少个B项 ...
- POJ3208 Apocalypse Someday(二分 数位DP)
数位DP加二分 //数位dp,dfs记忆化搜索 #include<iostream> #include<cstdio> #include<cstring> usin ...
- 搜索+剪枝 POJ 1416 Shredding Company
POJ 1416 Shredding Company Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 5231 Accep ...
- POJ 3216 Repairing Company(最小路径覆盖)
POJ 3216 Repairing Company id=3216">题目链接 题意:有m项任务,每项任务的起始时间,持续时间,和它所在的block已知,且往返每对相邻block之间 ...
- POJ-2018 Best Cow Fences(二分加DP)
Best Cow Fences Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10174 Accepted: 3294 Desc ...
- 【bzoj5174】[Jsoi2013]哈利波特与死亡圣器 二分+树形dp
题目描述 给你一棵以1为根的有根树,初始除了1号点为黑色外其余点均为白色.Bob初始在1号点.每次Alice将其中至多k个点染黑,然后Bob移动到任意一个相邻节点,重复这个过程.求最小的k,使得无论B ...
- poj - 1953 - World Cup Noise(dp)
题意:n位长的01序列(0 < n < 45),但不能出现连续的两个1,问序列有多少种. 题目链接:id=1953" target="_blank">h ...
- BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP+单调队列
BZOJ_1044_[HAOI2008]木棍分割_二分答案+DP Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个 ...
随机推荐
- Xshell连接不上行Linux系统
之前出现了.我的Linux系统上的主机可以ping通windows的一台电脑, windows也可以ping的通Linux.但是Xshell不能连接. 第一,我感觉是不是我Linux系统的端口被防火墙 ...
- php数据类型的true和false
- Java多线程系列 JUC线程池07 线程池原理解析(六)
关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...
- 【Linux不需要磁盘碎片整理的真正原因是因为Linux只是一个内核,它没有磁盘可以整理】
[Linux不需要磁盘碎片整理的真正原因是因为Linux只是一个内核,它没有磁盘可以整理]
- Fermat’s Chirstmas Theorem (素数打表的)
Fermat’s Chirstmas Theorem ...
- HTTPSQS(HTTP Simple Queue Service)消息队列
HTTPSQS(HTTP Simple Queue Service)是一款基于 HTTP GET/POST 协议的轻量级开源简单消息队列服务,使用 Tokyo Cabinet 的 B+Tree Key ...
- Docker-端口映射与容器互联
在使用docker过程中,通常会碰到需要多个服务组件容器共同协作的情况,这往往需要多个容器之间有能够互相访问到对方的服务除了通过网络访问外,Docker还提供了两个很方便的功能来满足服务访问的基本需求 ...
- linux学习系列二
vim是由vi发展而来,具有语法高亮显示,多视图编辑,代码折叠,支持插件等功能,vim成为了linux发行版本的标配. 1. vim工作模式 1. 普通模式:实现基本的光标移动和大量的快捷操作 2. ...
- Qt中 QTableWidget用法总结
转自--> http://edsionte.com/techblog/archives/3014 http://hi.baidu.com/fightiger/item/693aaa0f0f87d ...
- linux shell编程(二) 条件测试
bash中常用的条件测试有三种 条件测试的表达式:[ expression ] [[ expression]] 第一种:整数测试: -eq 测试两个整数是否相等,比如[ $A -eq $B ] -n ...