問題解決を最小限に抑えるために6つの演習を半値取得

タイトル説明

印刷の発明前に、本をコピーすることは、多くの作業が非常に困難な仕事であるが、我々は積極的に書籍を転写するために協力する必要がある、チームワークが非常に重要です。彼らはスクライブを補充することによって、作業の本を入力してコピーされるその時に、今書き写すとし\(M \)書籍、番号が\(メートル、2、3 ... \)を、それぞれの本は持っている\ (1 \ルのx \ル100000 \) ページ、これらの本が割り当てられている(k個\)\スクライブを、連続していなければならないそれらの本のスクライブに割り当てられた番号を必要とし、各書籍のみをすることができスクライブスクライブ。各スクライブ速度が同じである、あなたのタスクは、前提の下ですべての書籍が完成し、筆耕コピーされたページの少なくともそれぞれをコピーすることができるように、最適な物流計画を見つけることです。

入力形式

最初の行では、二つの整数があり、\(M及びK ,. 1 <= K、M <= 100000 \) 2行目、ある\(M \)整数\(X_I \)は、スペースで区切られました。これらの値はすべて正と比べて少ないです\(100000 \)

出力フォーマット

最高の流通スキームを表し、出力ライン数は、すべてのコピーがページの大半がコピーされたページの筆耕をコピーし、完了しています。

サンプル入力

9 3
100 200 300 400 500 600 700 800 900

サンプル出力

1700

トピック分析

2:この質問はアルゴリズムを必要とします。
動画説明住所:https://www.bilibili.com/video/av59514881/?p=3
この質問は半分答えはあります。
まず、我々は書くことができbool check(int num)、各スクライブに割り当てられて判断する機能\(numは\)ときブックのページ\(k個\)スクライブ超完成するかどうか\(m個\)ブック。あなたができる場合は、\(チェック(NUM)\)の戻りtrue、そうでない場合は、\(チェック(NUM)\)のリターンfalse
その後、我々は見つけます:

  • とき\(NUM = 0 \)する場合、\(チェックが(0)\)確かに戻りますfalse
  • \(NUM = \ sum_ {I = 1} ^ nx_i \) する場合、\(チェック(\ sum_ {I} = ^ nx_i。1)\)確かに返すtrueのみ1つのスクライブが終わりを転写することができるので、\ (M \)の本。

次に\(0 \)\(\ sum_ {I = 1 } ^ nx_i \) 最小の間に存在しなければならない\(NUM \)よう\(チェック(NUM)\)戻りますtrue

我々は見つけることができます:

  • 場合\(チェック(numは)\)を返すためにtrue、次に\(チェック(NUM + 1) 、チェック(NUM + 2)、......、チェック(\ sum_ {i = 1} ^ nx_i)\) を返しますtrue
  • もし(チェック(NUM-1)\ )\ 戻りfalse、次に\(チェック(NUM-2) 、検査(NUM-3)、...、チェック(0)\) リターンfalse

我々が答える必要があればnum独立変数を、答えは(設定することです\(チェック(NUM)\)従属変数として結果が返される)、我々は単調関数曲線は、独立変数が変化して、変数でなければなりません得ることができます。

次のようにコードは次のとおりです。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int m, k;   // m表示书有多少本,k表示抄写员的数量
long long a[maxn];  // a[i]表示第i本书的页数
// check函数用于判断分配给没个抄写员num页书的时候能否超写完
bool check(long long num) {
    int id = 1;     // id用于标记当前抄写员的编号,一开始id=1
    long long tot = 0;  // tot用于表示第id个抄写员目前已经抄写的书的页数
    for (int i = 0; i < m; i ++) {  // 循环遍历每一本书
        if (num - tot >= a[i]) {    // 如果第id个抄写员能够抄写第i本书,
            tot += a[i];        // 将tot+=a[i],因为tot表示第id个抄写员目前抄写的书
        }
        else if (a[i] > num)    // 如果a[i]>num,说明任何抄写员都抄写不了第i本书
            return false;
        else {
            id ++;  // id++,变成下一个抄写员的编号
            tot = a[i]; // 更新下一个抄写员已经抄写的书的页数为a[i],因为他目前只抄写了第i本书
            if (id > k) return false; // 如果id>k,说明k个抄写员已经不够用了,直接返回false
        }
    }
    return true;    // 返回true
}
int main() {
    cin >> m >> k;
    long long sum = 0;
    for (int i = 0; i < m; i ++) {
        cin >> a[i];
        sum += a[i];
    }
    long long L = 0, R = sum, res; // L记录答案的左边界,R记录答案的右边界,res记录答案
    while (L <= R) {
        long long mid = (L + R) / 2LL;
        if (check(mid)) {   // 找到当前最优解
            res = mid;      // 更新答案
            R = mid - 1;    // 看看有没有更优解
        }
        else L = mid + 1;   // 进有半部分找解
    }
    cout << res << endl;    // 输出答案
    return 0;
}

おすすめ

転載: www.cnblogs.com/zifeiynoip/p/11450631.html