1. 程式人生 > >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 copy. One of the most famous scribers lived in the 15th century and his name was Xaverius Endricus Remius Ontius Xendrianus (Xerox

). Anyway, the work was very annoying and boring. And the only way to speed it up was to hire more scribers.


Once upon a time, there was a theater ensemble that wanted to play famous Antique Tragedies. The scripts of these plays were divided into many books and actors needed more copies of them, of course. So they hired many scribers to make copies of these books. Imagine you have m

 books (numbered $1, 2, \dots, m$) that may have different number of pages ($p_1, p_2, \dots, p_m$) and you want to make one copy of each of them. Your task is to divide these books among k scribes, $k \le m$. Each book can be assigned to a single scriber only, and every scriber must get a continuous sequence of books. That means, there exists an increasing succession of numbers $0 = b_0 <b_1 < b_2, \dots < b_{k-1} \le b_k = m$
 such that i-th scriber gets a sequence of books with numbers between bi-1+1 and bi. The time needed to make a copy of all the books is determined by the scriber who was assigned the most work. Therefore, our goal is to minimize the maximum number of pages assigned to a single scriber. Your task is to find the optimal assignment.

Input 

The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case consists of exactly two lines. At the first line, there are two integers m and k$1 \le k \le m \le 500$. At the second line, there are integers $p_1, p_2, \dots p_m$ separated by spaces. All these values are positive and less than 10000000.

For each case, print exactly one line. The line must contain the input succession $p_1, p_2, \dots p_m$ divided into exactly k parts such that the maximum sum of a single part should be as small as possible. Use the slash character (`/') to separate the parts. There must be exactly one space character between any two successive numbers and between the number and the slash.


If there is more than one solution, print the one that minimizes the work assigned to the first scriber, then to the second scriber etc. But each scriber must be assigned at least one book.

2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100

題目大意:

要抄N本書,編號為1,2,3...N, 每本書有1<=x<=10000000頁, 把這些書分配給K個抄寫員,要求分配給某個抄寫員的那些書的編號必須是連續的。每個抄寫員的速度是相同的,求所有書抄完所用的最少時間的分配方案。

分析與總結:

所化的總時間取決於所有抄寫員中任務最多的那個,是經典的最大值最小化問題。LRJ《演算法入門經典》P151頁有介紹:


/**
*  最大值最小化問題: 二分法。  劉汝佳那本白書上也說的很詳細。
*     先把最大值的可能區間計算出來,也就是[0, maxAns] maxAns 就是所有頁數總和。
*  然後再在答案區間裡先把“最大值最小化”。
*     得到最小化後的最大值以後,就可以根據這個最大值來對最終答案進行計算。
*  如何分割槽,也就是計算最後答案ans:  這裡就要用到貪心思想,因為題目要求
*  如果有多種可能情況,讓區間集合所含的元素數從小到大排列。這樣就可以貪心地
*  從所有pages的最後一個元素往前遍歷來進行劃分區間,只要其總和不大於之前所求的最大值,
*  就歸到那個區間。
*     在把所有區間分好後,還有個情況就是,這個時候可能需要3個斜槓來分4個區間,
*  然而只用了2個(比如樣例2),這樣還有一個斜槓沒用到,就再用貪心,把pages從第一個開始往後掃,
*  如果當前pages不用劃斜槓,而剩餘斜槓數大於0,則在這裡添個斜槓。
*/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#define INF 0x7fffffff
#define MAXS 501
#define LL long long
using namespace std;
int m, k;
LL maxAns;
int pages[MAXS], ans[MAXS];

bool judge(LL x) {
    int sum = 0, t = k;
    for(int i = 0; i < m; i ++) {
        sum += pages[i];
        if(sum > x) {
            i --;
            sum = 0;
            t --;
        }
        if(!t) {
            if(i != m - 1) return false;
            else return true;
        }
    }
    return true;
}

void solve() {
    memset(ans, 0, sizeof(ans));
    LL l, r, cur;
    l = 0; r = maxAns;
    while(l < r) {
        cur = (l + r) / 2;
        if(judge(cur))   r = cur;
        else             l = cur + 1;
    }
    int sum = 0;
    for(int i = m - 1; i >= 0; i --) {
        sum += pages[i];
        if(sum > r) {
            sum = 0;
            ans[++ i] = 1;
            k --;
        }
    }
    int i = 1;
    while(k > 1) {
        for(; i < m; i ++ ) {
            if(!ans[i]) {
                ans[i] = 1;
                k --;
                break;
            }
        }
    }
    printf("%d", pages[0]);
    for(int i = 1; i < m; i ++) {
        if(ans[i]) printf(" /");
        printf(" %d", pages[i]);
    }
    printf("\n");
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t --) {
        maxAns = 0;
        scanf("%d%d", &m, &k);
        for(int i = 0; i < m; i ++) {
            scanf("%d", &pages[i]);
            maxAns += pages[i];
        }
        solve();
    }
    return 0;
}


相關推薦

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

Copying Books化問題

#include<stdio.h> #include<string.h> long long a[505]; int vis[505]; int ju(long long Ma

儘量

給出是個序列,如1 2 3 2 5 4 ,將其劃分成m個連續的子序列,每個子序列最少有一個元素,怎樣使每個子序列的和的最大值最小 #include <iostream> #include <ctime> using namespace std;

UVA 714 Copying Books二分查詢未a

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 cal

uva 714 Copying Books(二分法求

題目大意:將一個個數為n的序列分割成m份,要求這m份中的每份中值(該份中的元素和)最大值最小, 輸出切割方式,有多種情況輸出使得越前面越小的情況。 解題思路:二分法求解f(x), f(x) &l

UVa 714 Copying Books 二分 + 貪心 (化問題

/** * 最大值最小化問題: 二分法。 劉汝佳那本白書上也說的很詳細。 * 先把最大值的可能區間計算出來,也就是[0, maxAns] maxAns 就是所有頁數總和。 * 然後再在答案區間裡先把“最大值最小化”。 * 得到最小化後的最大值以後,就可

UVa 714 Copying Books——二分

注意上界在累加時可能超過int範圍 #include <cstdio> #include <cstring> #include <iostream> #includ

Java方法遍歷一次數組返回兩個結果

遍歷 get urn 個數 gets IV 限定 null int 使用內部類來存儲要返回的結果即可實現返回多個參數 使用泛型並限定類型必須實現Comparable接口,實現重用 使用T...a實現傳入不定量個數的數組 public class ArrayAlg{

鏈表結點的移動移到頭結點

gin 最大 -s nbsp printf type smo color padding #include<stdio.h>#include<stdlib.h>#define N 9typedef struct node{ int data;

鏈表結點的移動移到尾結點

anti pac fan 最大值 ont else pad reat sed #include<stdio.h>#include<stdlib.h>#define N 9typedef struct node{ int data; stru

UVa 11082 - Matrix Decompressing

增加 new cst 根據 ros 輸入 memset times mincut 鏈接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob

Hard Life UVA - 1389密度子圖 輸出點集

題意:   rt 解析:   我用的第二種方法。。。   s向所有的邊連權值為1的邊   所有的點向t連權值為mid的邊   如果存在u -  > v  則邊向u和v分別連一條權值為INF的邊   二分mid   用dfs從s 順著邊走標記點   然後輸出1 - n

UVA(714) Copying Books

最大值最小化應該是二分法中經典的題目,Copying Books就是一道最大值最小化的題目 題目大致的意思是要抄N本書,編號為1,2,3...N, 每本書有1<=x<=10000000頁, 把這些書分配給K個抄寫員,要求分配給某個抄寫員的那些書的編號必須是連續的。每個抄寫員的速度是相同的,求所有

mysql 資料型別

1、整型 MySQL資料型別    含義(有符號) tinyint(m)    1個位元組  範圍(-128~127) smallint(m)    2個位元組  範圍(-32768~32767) mediumint(m)    3個位元組  範圍(-8388608

B - Aggressive cows POJ - 2456

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0

UVa 714 Copying Books(貪心 二分)

題意  把m數分成k組  使每組數的和的最大值最小  如果有多種分法 靠前的組的和儘量小 關鍵是找出那個最小的最大值   可以通過二分來找出  開始左端點為m個數中最大的數  右端點為m個數的和  若中點能將m個數分為小於等於k組  比它大的肯定都是可以的  中點變為右端點

索引堆

堆 堆 引言 最大堆 最大索引堆 索引堆定義 索引堆實現 總結 引言 ​ 堆是電腦科學中一類特殊的資料結構,它雖然也被叫做優先佇列,但它並不是佇列,它並不是按照先進先出的原則進行儲存資料的,它更像是一棵二叉樹。 最大堆

UVa:714 Copying Books .

最大值最小化的問題,卡了兩天才做出來。 入門經典上有分析,但是隻提供了求最小的最大值的思路。 具體方法是在某區間上用二分法猜數字,最後猜的一個數x是使得【將輸入數列劃分成m個連續子序列使得所有S(i)均不超過x】成立的最小x,這就是最小的最大值。 這裡二分的並非陣列,

Monthly Expense 化+二分

Farmer John is an astounding accounting wizard and has realized he might run out of money to run t

HDU 4309 Seikimatsu Occult Tonneru流+二進制枚舉

emp puts open 通過 txt add 枚舉 sin ridge http://acm.hdu.edu.cn/showproblem.php?pid=4309 題意: 有n個城市,每個城市有num[i]個居民,有敵人要進行地毯式轟擊,居民們要逃到隧道去。現在有