UVa 714 Copying books 贪心+二分 最大值最小化

题目大意:

要抄N本书,编号为1,2,3...N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的。每个抄写员的速度是相同的,求所有书抄完所用的最少时间的分配方案。

题目中的要求是去求划分的子序列的最大值尽量小,最大值最小化,如果从划分的角度看,无法获得好的思路,我们可以从值得角度考虑,所要求的最小的最大值必定是从[amax,sum(总和)]中取得的,那么我们可以二分法的方式猜测一个数字,看它是否满足要求,如果满足要求,我们可以继续缩小范围。

实现的另一个关键是划分,题目说如果有多解的话,前面的要求尽量小,那么我们的划分必然是从右往左划分,我们可以先做判断,如果都要求划分的值尽量达到最大值,它的划分个数小于要求的划分数,它就是满足条件的,因为我们可以将某一个划分组的序列拆解下来(子序列在拆解),它也一定是满足条件的,因为小于最大值肯定是对的,在贪心的过程中,一旦还需要划分组数正好等还剩下的整数数量的话,直接将每一个数作为一个划分组即可。

下面一篇博文将重点介绍一下二分查找的有关细节。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 505
 4 using namespace std;
 5 int num[MAXN];
 6 int mark[MAXN];
 7 int n,m,k;
 8 long long low=-1,high=0;
 9 void init(){
10     low = -1;
11     high = 0;
12     memset(mark,0,sizeof(mark));
13 }
14 bool solve(long long mid){
15     //进行判断是否可以划分为某个最小最大值的序列
16     long long sum=0;
17     int t=1;
18     for(int i = m-1;i >=0 ; i--){
19         if(sum + num[i] > mid){
20             sum = num[i];
21             t++;
22             if(t > k)
23                 return false;
24         }
25         else
26             sum += num[i];
27     }
28     return true;
29 }
30 void print(long long s){
31     long long sum = 0;
32     int t = 1,i,j;
33     for(i = m-1;i >=0 ; i--){
34         if(sum + num[i] > s){
35             //贪心的关键,尽量值靠近最大值
36             sum = num[i];
37             mark[i] = 1;
38             t++;
39         }
40         else{
41             sum +=num[i];
42         }
43         if(k - t == i + 1){
44             //贪心的关键
45             //如果剩下来的值的数量正好等于要划分的组数那么每一个数为一组
46             for(j = 0 ;j <= i; j++){
47                 mark[j] = 1;
48             }
49             break;
50         }
51     }
52     for(i = 0 ;i < m-1 ; i++){
53         printf("%d ",num[i]);
54         if(mark[i]==1){
55             printf("/ ");
56         }
57     }
58     printf("%d\n",num[m-1]);
59 }
60 int main(){
61     long long left,right,mid;
62     scanf("%d",&n);
63     while(n--){
64         init();
65         scanf("%d%d",&m,&k);
66         for(int i = 0 ; i < m ;i++){
67             scanf("%d",&num[i]);
68             if(low < num[i])
69                 low = num[i];
70             high+=num[i];
71         }
72         left = low;
73         right = high;
74         while(left <= right){
75             memset(mark,0,sizeof(mark));
76             mid = left + (right - left)/2;
77             if(solve(mid)){
78                 right = mid - 1;
79             }
80             else
81             {
82                 left = mid + 1;
83             }
84         }
85         print(left);
86     }
87     return 0;
88 }
时间: 2024-10-03 00:00:09

UVa 714 Copying books 贪心+二分 最大值最小化的相关文章

UVa 714 Copying Books(贪心 二分)

题意  把m数分成k组  使每组数的和的最大值最小  如果有多种分法 靠前的组的和尽量小 关键是找出那个最小的最大值   可以通过二分来找出  开始左端点为m个数中最大的数  右端点为m个数的和  若中点能将m个数分为小于等于k组  比它大的肯定都是可以的  中点变为右端点   否则中点变成左端点 然后就可以贪心逆向模拟了  从后往前每组选择尽量多的数直到剩下的数等于组数 #include <bits/stdc++.h> using namespace std; typedef long lo

uva 714 Copying Books (二分)

uva 714 Copying Books Before the invention of book-printing, it was very hard to make a copy of a book. All the contents had to be re-written by hand by so called scribers. The scriber had been given a book and after several months he finished its co

【NOIP提高组2015D2T1】uva 714 copying books【二分答案】——yhx

Before the invention of book-printing, it was very hard to make a copy of a book. All the contents hadto be re-written by hand by so called scribers. The scriber had been given a book and after severalmonths he finished its copy. One of the most famo

uva 714 - Copying Books(贪心 最大值最小化 二分)

题目描述开头一大堆屁话,我还仔细看了半天..其实就最后2句管用.意思就是给出n本书然后要分成k份,每份总页数的最大值要最小.问你分配方案,如果最小值相同情况下有多种分配方案,输出前面份数小的,就像字典序输出从小到大一样的意思. 这里用到贪心的方法,定义f(x)为真的条件是满足x为最大值使n本书分成k份,那么就是求x的最小值.如何确定这个x就是用的二分法,x一定大于0小于所有值的合,不断的二分再判断是否成立,成立就取左半边,不成立说明太小了就取右半边,写的时候还是没有把二分法理解透彻,我还怕会丢失

UVa 714 - Copying Books 二分答案

题目链接:714 - Copying Books 解题思路 具体处理方法见代码 /************************************************************** Problem: User: youmi Language: C++ Result: Accepted Time: Memory: ****************************************************************/ //#pragma comm

uva--714+二分(最大值最小化问题)

题意: 原题意比较啰嗦,大概的意思就是输入n个整数,然后将他们分成m段,要求求出这m段中最大和最小时候的情况.输出的时候段与段之间用"/"分离,当有多个解时,输出第一段值最小的,第一段相同时输出第二段值最小的解,以此类推. 思路: 一看到最大值最小,我就想到了二分,可以采取二分试探这个最大值,然后看是否能在这个最大值下能否分成m段,然后我们记录下二分过程中得到的那个满足要求的最小的值:对于这个题目的输出,我们可以采取贪心的策略:我们从最后一段开始分,在满足条件的情况使得后面的段尽量长:

UVA 714 Copying Books 抄书 (二分)

题意:把一个包含m个正整数的序列划分成k个非空的连续子序列.使得所有连续子序列的序列和Si的最大值尽量小. 二分,每次判断一下当前的值是否满足条件,然后修改区间.注意初始区间的范围,L应该为所有正整数中的最大值,否则应该判断时注意.输出解的时候要使字典序最小,所以从后面贪心. #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxm = 501; ll p[maxm]; bool vis[

714 - Copying Books(二分)

该题是所谓"最大值尽量小"的典型代表,方法就是用二分猜这个最值,判断函数就是从前向后扫,尽量向后划,如果最后划出的组数比k小,那么显然可以划成k组. 代码如下: #include<bits/stdc++.h> using namespace std; typedef long long ll; int T,n,k,a[505]; bool P(int m) { int ans=0,cnt=1; for(int i=0;i<n;i++) { ans+=a[i]; if(

UVA 714 Copying Books

题意: 要抄N本书,编号为1,2,3...N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的.每个抄写员的速度是相同的,求所有书抄完所用的最少时间的分配方案. 分析: 这个题以前做过.就是先二分出来,最大的区间最小值.然后一重循环查找输出/就好 代码: #include <iostream>#include <cstring>#include <cstdio>#include <al