UVA(714) Copying Books
阿新 • • 發佈:2018-12-01
最大值最小化應該是二分法中經典的題目,Copying Books就是一道最大值最小化的題目
題目大致的意思是要抄N本書,編號為1,2,3...N, 每本書有1<=x<=10000000頁, 把這些書分配給K個抄寫員,要求分配給某個抄寫員的那些書的編號必須是連續的。每個抄寫員的速度是相同的,求所有書抄完所用的最少時間的分配方案。
設序列的最大值為max,總的和為sum。很顯然序列的最大值在[max,sum]之間,找到了上界和下界就可以二分查詢。在每次查詢的時候,我們可以儘量向右劃分,這樣可以使劃分的最大值儘量最小。如果小於等於查詢的數,r = mid,反之 i = mid + 1。找到了最大值中的最小值之後就可以進行劃分,劃分時只要反向遍歷陣列,將每個區間儘量向左劃即可。不過要注意用 資料過大,要用long long儲存,否則會溢位。
題目可以在UVA上提交,不過UVA測評的速度太慢了,可以在https://vjudge.net這個網站上提交。下面是AC的程式碼。
#include <stdio.h> #include <stdlib.h> #include<iostream> #include<algorithm> #include<memory> #include<limits.h> using namespace std; int n,k,m; int arr[501],ans[501]; int findMid(long long num) { long long sum = 0,count1 = 0; for(int i = 0;i < m;++i) { if(count1 > k - 1) return 0; sum += arr[i]; if(sum > num) { sum = arr[i]; ++count1; } } if(count1 > k - 1) return 0; return 1; } void divid(long long num) { long long sum = 0,count1 = 0; for(int i = m - 1;i >= 0;--i) if(sum + arr[i] > num) { ans[i + 1] = 1; sum = arr[i]; count1++; } else sum += arr[i]; int i = 1; while(i < m && count1 < k - 1) { if(!ans[i]) ans[i] = count1++; ++i; } } int main() { cin >> n; while(n) { memset(arr,0,sizeof(arr)); memset(ans,0,sizeof(ans)); long long sum = 0; int max1 = INT_MIN; cin >> m >> k; for(int i = 0;i < m;++i) { cin >> arr[i]; sum += arr[i]; max1 = max(max1,arr[i]); } long long i = max1,j = sum + 1,mid; while(i < j) { mid = (i + j) / 2; if(findMid(mid)) j = mid; else i = mid + 1; } divid(i); for(int i = 0;i < m - 1;++i) { if(ans[i]) cout << '/' << ' '; cout << arr[i] << ' '; } if(ans[m - 1]) cout << '/' << ' '; cout << arr[m - 1] << endl; --n; } return 0; }