Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
Input
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。
Solution
先排序,二分能得到几块木板,然后搜索一下能不能切出这么多木块。详见代码。
思路借鉴了这位同学:http://www.cnblogs.com/2014nhc/p/6198644.html
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 int a[1111],b[1111],c[1111]; 7 int n,m,tot,w,mid; 8 9 bool check(int x) 10 { 11 bool fg; 12 if (w>tot-c[mid]) return false; 13 if (x==0) return true; 14 for (int i=1; i<=m; i++) 15 if (a[i]>=b[x]) 16 { 17 a[i]-=b[x];//切掉这块 18 if (a[i]<b[1]) w+=a[i];//如果比最小的一块还要小,则算作废料 19 fg=check(x-1); 20 if (a[i]<b[1]) w-=a[i];//回溯 21 a[i]+=b[x]; 22 if (fg) return true; 23 } 24 return false; 25 } 26 27 int main() 28 { 29 cin>>m; 30 for (int i=1; i<=m; i++) 31 { 32 cin>>a[i]; 33 tot+=a[i]; 34 } 35 cin>>n; 36 for (int i=1; i<=n; i++) 37 cin>>b[i]; 38 sort(a+1,a+m+1); sort(b+1,b+n+1); 39 for (int i=1; i<=n; i++) 40 c[i]=c[i-1]+b[i]; 41 while (c[n]>tot) n--; 42 int left=0,right=n,ans=0; 43 while (left<=right) 44 { 45 w=0; 46 mid=(left+right)/2; 47 if (check(mid)) {ans=mid; left=mid+1;} 48 else right=mid-1; 49 } 50 cout<<ans<<endl; 51 return 0; 52 }
Source
http://www.lydsy.com/JudgeOnline/problem.php?id=1082