抄书问题
来源:互联网 发布:软件license 华为 编辑:程序博客网 时间:2024/04/29 17:29
有n本书和k个抄写员。要求n本书必须连续地分配给这k个抄写员抄写。也就是说前a1本书分给第一个抄写员,接下来a2本书分给第二个抄写员,如此类推(a1,a2需要你的算法来决定)。给定n,k和每本书的页数p1,p2..pn,假定每个抄写员速度一样(每分钟1页),k个抄写员同时开始抄写,问最少需要多少时间能够将所有书全部抄写完工?
样例
Given array A = [3,2,4]
, k = 2
.
Return 5
( First person spends 5 minutes to copy book 1 and book 2 and second person spends 4 minutes to copy book 3. )
解答
解法1:动态规划
设f[i][j]代表前i本书分给j个抄写员抄完的最少耗时。答案就是f[n][k]。状态转移方程f[i][j] = min{max(f[x][j-1], sum(x+1, i)), j<x<i}。其中x是在枚举第j个抄写员是从哪本书开始抄写。
时间复杂度O(n^2*k)
解法2;动态规划+决策单调。
同上一解法,但在x的枚举上进行优化,设s[i][j]为使得f[i][j]获得最优值的x是多少。有s[i][j+1]>=s[i][j]>=s[i-1][j]。因此x这一层的枚举不再是每次都是n而是总共加起来n。
时间复杂度O(n*k)
解法3:二分答案
二分答案,然后尝试一本本的加进来,加满了就给一个抄写员。看最后需要的抄写员数目是多余k个还是少于k个,然后来决定是将答案往上调整还是往下调整。其实可以这样想:如果一个人抄书那么耗时 maxTime , which is the sum of all pages (上限).
如果有足够多人,则最小耗时为所有书中最大值 (下限)
答案必然在minTime and maxTime 之间, 用 二分法找出满足条件的答案
时间复杂度O( n log Sum(pi) )
// http://www.jiuzhang.com/problem/2/class Solution {public: /** * @param pages: a vector of integers * @param k: an integer * @return: an integer */ // 解法1: 动态规划 // 设f[i][j]代表前i本书分给j个抄写员抄完的最少耗时。答案就是f[n][k]。 // 思考最后一个人需要抄几本书 // 状态转移方程f[i][j] = min{max(f[x][j-1], sum(x+1, i)), j<x<i}。其中x是在枚举第j个抄写员是从哪本书开始抄写。 // 时间复杂度O(n^2*k) int copyBooks1(vector<int> &pages, int k) { // write your code here int n = pages.size(); // book number if(n == 0){ return 0; } int ans = 0; //预处理边界条件 if(k > n){ for(int i = 0; i < n; i++){ ans = max(ans, pages[i]); } return ans; } //f[i][j] 表示前i本书分给j给人抄的最少花费时间 vector<vector<int> > f(n+1, vector<int>(k+1, 0)); int maxPage = 0; for(int i = 0; i < n; i++){ maxPage = max(maxPage, pages[i]); } for(int i = 1; i <= n; i++){ f[i][0] = numeric_limits<int>::max(); } // prepare sum start vector<int> sum(n, 0); // sum[i] 表示从pages[0]到pages[i]的前缀和 sum[0] = pages[0]; for(int i = 1; i < n; i++){ sum[i] = pages[i] + sum[i-1]; } // prepare sum end for(int i = 1; i <= n; i++){ for(int j = 1; j <= k; j++){ int minTime = numeric_limits<int>::max(); for(int x = j-1; x < i; x++) { // 枚举最后一个人从哪本书开始抄 // x表示前面j-1 个人抄x本书(至少j-1本,否则不够抄), // 最后一个人抄第x+1本(下标x)到最后第i本(下标i-1) minTime = min(minTime, max(f[x][j-1], sum[i-1] - sum[x-1])); } f[i][j] = minTime; } } return f[n][k]; } // 解法2: 二分法 // 二分答案,然后尝试一本本的加进来,加满了就给一个抄写员。 // 看最后需要的抄写员数目是多余k个还是少于k个,然后来决定是将答案往上调整还是往下调整。 // 时间复杂度O( n log Sum(pi) ) int copyBooks(vector<int> &pages, int k) { int n = pages.size(); // book number if(n == 0){ return 0; } int ans = 0; //预处理边界条件 if(k > n){ for(int i = 0; i < n; i++){ ans = max(ans, pages[i]); } return ans; } int minTime = numeric_limits<int>::min(); int maxTime = 0; for(int i = 0; i < n; i++){ minTime = max(minTime, pages[i]); // min of books maxTime += pages[i];// sum of all } //可以这样想:如果一个人抄书那么耗时 maxTime , which is the sum of all pages (上限). // 如果有足够多人,则最小耗时为所有书中最大值 (下限) //答案必然在minTime and maxTime 之间 // 二分法找出满足条件的答案 int start = minTime, end = maxTime; while(start < end){ int mid = start + (end - start) / 2; if(search(mid, pages, k)){ // 此时已经满足条件n本书由k个人抄完,但是我们要找最小费时,所以继续往左边区间找 // 由于mid 是可能的答案之一,所以不能mid-1. end = mid; } else { // 在mid时间内无法抄完 start = mid + 1; } } return start; } // search 函数返回值表示k个人在target 时间能否抄完所有书 bool search(int target, vector<int> &pages, int k){ int count = 1; // how many people needed int sum = 0; int i = 0; while(i < pages.size()){ if(sum + pages[i] <= target){ // 每个人在target时间内尽量多抄 sum += pages[i++]; } else if(pages[i] <= target){ count++;//上一个人抄不完,由另外一个人抄 sum = pages[i++]; } else { // 单本书就已经超时了,直接return return false; } } return count <= k; }};
- 抄书问题
- 抄书问题
- 抄书问题
- 3162 抄书问题
- Codevs3162抄书问题题解
- 抄书问题之二
- codevs-3162 抄书问题
- codevs 抄书问题系列
- codevs 3162 抄书问题
- [DP] [贪心] [CodeVS3162] 抄书问题
- WIKIOI 3162 抄书问题 题解与分析
- CODEVS 3162 抄书问题 (复制书稿)
- Codevs 抄书问题1&2&3
- Uva 714 (抄书问题,二分查找+贪心)
- WIKIOI 3163 抄书问题2 题解与分析
- 九章算法面试题2 抄书问题
- CODEVS 3162 3163 3168 抄书问题1 2 3
- codevs 3162 抄书问题 (dp+枚举输出位置)
- iOS_UIImageView的contentMode属性--照片的显示模式
- vim中的杀手级插件: vundle
- 左边固定 右边自适应
- 新的时代新的教育
- hdu1077模拟
- 抄书问题
- 学习React Native(二)HelloWorld
- android:clipChildren妙用:底部的radioGroup中间的button突出
- BestCoder Round #64 (div.1) A.Sum
- 单链队列——队列的链式存储结构
- 【Ubuntu下安装配置】右键终端、google-chrome安装、sogou拼音安装
- cpu控制器
- 制作能够显示数学公式以及进行交互式图形绘制的静态页面
- 实用的签到、日程表日历控件(可扩展)