BZOJ1082: [SCOI2005]栅栏
【传送门:BZOJ1082】
简要题意:
给出m块有长度的可切割木板,n块有长度的需要木板,求出最多能够切割出多少块需要木板
题解:
二分答案,然后用搜索来判断这个答案是否能够达到,比较简单
但是需要剪枝,其实就是减去一些不必要的搜索,先快排两种木板,如果最小需要的木板比可切割的一些木板还要大的话,证明这些可切割木板没用,如果可切割的最大木板比一些需要的木板小,证明这些需要的木板无法符合条件
参考代码:
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> typedef long long LL; using namespace std; 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() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&b[i]); 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)/2; flag=0; dfs(1,mid,0); if(flag!=0)ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚