[洛谷P1528] 切蛋糕

洛谷题目链接:切蛋糕

题目描述

Facer今天买了n块蛋糕,不料被信息组中球球等好吃懒做的家伙发现了,没办法,只好浪费一点来填他们的嘴巴。他答应给每个人留一口,然后量了量每个人口的大小。Facer有把刀,可以切蛋糕,但他不能把两块蛋糕拼起来,但是他又不会给任何人两块蛋糕。现在问你,facer怎样切蛋糕,才能满足最多的人。(facer的刀很强,切的时候不会浪费蛋糕)。

输入输出格式

输入格式:

第一行n,facer有n个蛋糕。接下来n行,每行表示一个蛋糕的大小。再一行一个数m,为信息组的人数,然后m行,每行一个数,为一个人嘴的大小。(1<=n<=50, 1<=m<=1024)

输出格式:

一行,facer最多可以填多少张嘴巴。

输入输出样例

输入样例#1:
4
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30

输出样例#1:
7

简述一下题意:给出\(n\)块蛋糕的大小和\(m\)个人要吃的量.现在只允许切蛋糕,求最多能满足多少人的需求.


我们并不知道最终能满足多少人,但是很显然,肯定要优先满足需求较小的人.所以可以现将每个人的需求排个序,这样口的大小的数组就是单调的了.既然是单调的,就可以用二分来确定最多能否满足前mid个人.前mid个人能否满足直接爆搜就可以了.


然而,这样并过不了,因为数据范围,这么搞是肯定要TLE的.所以我们可以考虑一下剪枝.

  • 因为口的大小是单调的,所以如果第\(i\)个人和第\(i-1\)个人的口大小相同,不能满足第\(i\)个人就不能满足第\(i-1\)个人.
  • 因为每次切都会有浪费(搜索过程中并不知道哪些一定可以作为浪费,但是如果第一个人都无法满足就一定是浪费了的),所以可以吧浪费的统计下来,那么如果蛋糕的总和减去浪费的总量小于前\(mid\)个人的口的大小,则不论怎么搜,都搜不出结果.
  • 然后就是在搜索的过程中可以先从第\(mid\)个开始往第一个搜,因为能满足第\(mid\)人的情况比较少,可以减少分支.
#include<bits/stdc++.h>
using namespace std;
const int N=50+5;
const int M=1024+5;

int n, m, ans = 0, waste = 0;
int cake[N], temp[N], sum = 0;
int mouth[M], pre[M];

bool dfs(int person,int pos,int mid){
    if(person == 0) return true;
    if(sum-waste < pre[mid]) return false;
    for(int i=pos;i<=n;i++){
        if(temp[i] < mouth[person]) continue;
        temp[i] -= mouth[person];
        if(temp[i] < mouth[1]) waste += temp[i];
        if(mouth[person] == mouth[person-1]){
            if(dfs(person-1,i,mid)) return true;
        }
        else if(dfs(person-1,1,mid)) return true;
        if(temp[i] < mouth[1]) waste -= temp[i];
        temp[i] += mouth[person];
    }
    return false;
}

bool check(int mid){
    memcpy(temp,cake,sizeof(temp));
    waste = 0; bool res = dfs(mid,1,mid);
    if(res) return true;
    return false;
}

int main(){
    //freopen("data.in","r",stdin);
    cin >> n;
    for(int i=1;i<=n;i++) cin >> cake[i], sum += cake[i];
    cin >> m;
    for(int i=1;i<=m;i++) cin >> mouth[i];
    sort(mouth+1 , mouth+m+1); sort(cake+1 , cake+n+1);
    for(int i=1;i<=m;i++) pre[i] = pre[i-1]+mouth[i];
    int l = 0, r = m, mid;
    while(pre[r] > sum) r--;
    while(l <= r){
        mid = (l+r>>1);
        if(check(mid)) l = mid+1, ans = mid;
        else r = mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BCOI/p/8931681.html