Peter's codebook A blog full of codes

POJ 3273 Monthly Expense

Binary Search

傳送門

POJ3273

解題想法

最大值最小化 => 二分搜尋

用二分搜去找到最低的最高花費。 check(d) 代表限制 fajomonth 最大的大小是 d ,是否能夠湊出數量 M 個 jajomonth 。

檢查的策略是,依序把每天的花費加起來,若有其中一天超過 d 則失敗,若發現 jajomonth 大小超過 d 則增加 jajomonth 數量,如果 jajomonth 的數量 > 題目的 M ,則失敗。

之後用二分搜找到 check(d) = true 的下界。

程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

class Solution{
    private:
        vector<int>data;
        int N, M;
        inline void readIO(void) {
            scanf("%d%d",&N,&M);
            for(int i=0; i<N; ++i) {
                int t; scanf("%d",&t);
                data.push_back(t);
            }
        }
        bool check(int d) {
            int counter=1;
            int sum=0;
            for(int i=0; i<N; ++i) {
                if(data.at(i)>d) return false;
                int t=sum+data.at(i);
                if(t <= d ) sum+=data.at(i);
                else { // t > d
                    sum=data.at(i);
                    ++counter; // start new set
                }
                if(counter>M) return false;
            }
            return true;
        }
        int sol(void) {
            int lb=0, ub=1e9+7;
            while(ub-lb>1) {
                int mid=((unsigned int)lb+(unsigned int)ub)>>1;
                if(check(mid)) ub=mid;
                else lb=mid;
            }
            return ub;
        }
    public:
        void mainLoop(void) {
            data.clear();
            readIO();
            printf("%d\n", sol());
        }
};

int main(void) {
    Solution sol;
    sol.mainLoop();
    return 0;
}
comments powered by Disqus