易水人去,明月如霜。
Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购
买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
最多能够得到多少他所需要的木板。
Input
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长
度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。
Sample Input
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30
Sample Output
HINT
25切出 21 30切出 20 40切出 19、18 50切出 15、16、17
思路:直接暴搜,但是加的优化很多,下面列举一下主要的
1.对现有和所需排序,之后搜索的时候一定是先满足小的需求再满足大的需求(贪心思路)
2.对于现有木材中的max,凡是需求中大于max的,都可以直接扔掉不要,因为它们一定切不出来(同样可用于需求中的min)
3.二分,在0-m中二分判断是否可以达到mid,一定是从1-mid块木板(已升序排列)中切最优
4.如果剩余木材小于还没切但要切的需求总量,就返回
5.如果是相同的需求,我们可以让它们强制有序,即i需求用j木材切,若i+1需求与i相同,则i+1一定用大于等于j木材切
还有一些po主自己加的,不知道能优化多少
6.随便搞个贪心,算一下浪费量trash,在搜索中可以进行判断,如果浪费更多了那必定不优于最初的贪心(代码中的实现不尽人意,应该还能在精进一下,比如每次算出更优答案时可以更新浪费量trash)
7.接上面,顺便算出最初贪心时能切minn块,然后答案一定是在minn-m间,比0-m要优
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int read()
{
char ch;int s=0,f=1;ch=getchar();
while(ch>'9'||ch<'0') { if(ch=='-') f*=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=s*10+ch-48,ch=getchar();
return s*f;
}
bool flag;
int n,m,mid;
int a[55],b[1005],bl[1005];
ll sa;
int sb[1005];
void dfs(int ak,int bk,int w)
{
if(bk==0)flag=1;
while(ak<=n&&a[ak]<b[1]){w+=a[ak];ak++;}
if(flag||ak>n)return;
if(w+sb[mid]>sa)return;
int t=ak,t1=ak,t2=bk,t3=w;
if(b[bk]==b[bk+1]&&bk!=mid)t=bl[bk+1];
for(int i=t;i<=n;i++)
if(a[i]>=b[bk])
{
bl[bk]=i;a[i]-=b[bk];
bk--;
dfs(ak,bk,w);
ak=t1;bk=t2;w=t3;a[i]+=b[t2];
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)a[i]=read();
m=read();
for(int i=1;i<=m;i++)b[i]=read();
sort(a+1,a+n+1);
sort(b+1,b+m+1);
while(b[m]>a[n])m--;
int tot=0;
for(int i=1;i<=n;i++)
if(a[i]>b[1])a[++tot]=a[i];
n=tot;
for(int i=1;i<=n;i++)sa+=a[i];
for(int i=1;i<=m;i++)sb[i]=sb[i-1]+b[i];
int l=1,r=m,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
flag=0;dfs(1,mid,0);
if(flag)ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}