洛谷 P3040 [USACO12JAN]贝尔分享Bale Share

P3040 [USACO12JAN]贝尔分享Bale Share

题目描述

Farmer John has just received a new shipment of N (1 <= N <= 20) bales of hay, where bale i has size S_i (1 <= S_i <= 100). He wants to divide the bales between his three barns as fairly as possible.

After some careful thought, FJ decides that a "fair" division of the hay bales should make the largest share as small as possible. That is, if B_1, B_2, and B_3 are the total sizes of all the bales placed in barns 1, 2, and 3, respectively (where B_1 >= B_2 >= B_3), then FJ wants to make B_1 as small as possible.

For example, if there are 8 bales in these sizes:

2 4 5 8 9 14 15 20

A fair solution is

Barn 1: 2 9 15 B_1 = 26 Barn 2: 4 8 14 B_2 = 26 Barn 3: 5 20 B_3 = 25 Please help FJ determine the value of B_1 for a fair division of the hay bales. 

FJ有N (1 <= N <= 20)包干草,干草i的重量是 S_i (1 <= S_i <= 100),他想尽可能平均地将干草分给3个农场。

他希望分配后的干草重量最大值尽可能地小,比如, B_1,B_2和 B_3是分配后的三个值,假设B_1 >= B_2 >= B_3,则他希望B_1的值尽可能地小。

例如:8包干草的重量分别是:2 4 5 8 9 14 15 20,一种满足要求的分配方案是

农场 1: 2 9 15 B_1 = 26

农场 2: 4 8 14 B_2 = 26

农场 3: 5 20 B_3 = 25

请帮助FJ计算B_1的值。

输入输出格式

输入格式:

 

  • Line 1: The number of bales, N.

  • Lines 2..1+N: Line i+1 contains S_i, the size of the ith bale.

 

输出格式:

 

  • Line 1: Please output the value of B_1 in a fair division of the hay bales.

 

输入输出样例

输入样例#1: 复制
8 
14 
2 
5 
15 
8 
9 
20 
4 
输出样例#1: 复制
26 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 30
using namespace std;
int n;
int A,B,C;
int ans=0x7f7f7f7fl;
int sum[MAXN];
void dfs(int now){
    if(max(A,max(B,C))>ans)    return ;
    if(now==n+1){
        ans=max(A,max(C,B));
        return;
    }    
    A+=sum[now];dfs(now+1);A-=sum[now]; 
    B+=sum[now];dfs(now+1);B-=sum[now]; 
    C+=sum[now];dfs(now+1);C-=sum[now];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&sum[i]);
    dfs(1);
    cout<<ans;
}
60分的dfs
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 30
using namespace std;
int n;
int A,B,C;
int ans=0x7f7f7f7fl;
int sum[MAXN];
void dfs(int now){
    if(now==n+1){
        ans=max(A,max(C,B));
        return;
    }
    A+=sum[now];if(A<ans)    dfs(now+1);A-=sum[now]; 
    B+=sum[now];if(B<ans)    dfs(now+1);B-=sum[now]; 
    C+=sum[now];if(C<ans)    dfs(now+1);C-=sum[now];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&sum[i]);
    dfs(1);
    cout<<ans;
}
AC的dfs

正解思路:动态规划。

f[i][j][k]表示到第i堆干草为止,第一个农场分到j的干草,第二个农场分到k的干草。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 10010
using namespace std;
int n;
int dp[23][2010][2010];
int num[MAXN],sum[MAXN];
int dfs(int now,int x,int y){
    int z=sum[now-1]-x-y;
    if(now==n+1)    return max(x,max(y,z));
    if(dp[now][x][y])    return dp[now][x][y];
    dp[now][x][y]=min(dfs(now+1,x+num[now],y),min(dfs(now+1,x,y+num[now]),dfs(now+1,x,y)));
    return dp[now][x][y];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)    scanf("%d",&num[i]);
    for(int i=1;i<=n;i++)    sum[i]=sum[i-1]+num[i];
    dfs(1,0,0);
    cout<<dp[1][0][0];
}

转载于:https://www.cnblogs.com/cangT-Tlan/p/8025070.html

好的,这是一道经典的单调栈问题。题目描述如下: 有 $n$ 个湖,第 $i$ 个湖有一个高度 $h_i$。现在要在这些湖之间挖一些沟渠,使得相邻的湖之间的高度差不超过 $d$。请问最少需要挖多少个沟渠。 这是一道单调栈的典型应用题。我们可以从左到右遍历湖的高度,同时使用一个单调栈来维护之前所有湖的高度。具体来说,我们维护一个单调递增的栈,栈中存储的是湖的下标。假设当前遍历到第 $i$ 个湖,我们需要在之前的湖中找到一个高度最接近 $h_i$ 且高度不超过 $h_i-d$ 的湖,然后从这个湖到第 $i$ 个湖之间挖一条沟渠。具体的实现可以参考下面的代码: ```c++ #include <cstdio> #include <stack> using namespace std; const int N = 100010; int n, d; int h[N]; stack<int> stk; int main() { scanf("%d%d", &n, &d); for (int i = 1; i <= n; i++) scanf("%d", &h[i]); int ans = 0; for (int i = 1; i <= n; i++) { while (!stk.empty() && h[stk.top()] <= h[i] - d) stk.pop(); if (!stk.empty()) ans++; stk.push(i); } printf("%d\n", ans); return 0; } ``` 这里的关键在于,当我们遍历到第 $i$ 个湖时,所有比 $h_i-d$ 小的湖都可以被舍弃,因为它们不可能成为第 $i$ 个湖的前驱。因此,我们可以不断地从栈顶弹出比 $h_i-d$ 小的湖,直到栈顶的湖高度大于 $h_i-d$,然后将 $i$ 入栈。这样,栈中存储的就是当前 $h_i$ 左边所有高度不超过 $h_i-d$ 的湖,栈顶元素就是最靠近 $h_i$ 且高度不超过 $h_i-d$ 的湖。如果栈不为空,说明找到了一个前驱湖,答案加一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值