【bzoj1082】[SCOI2005]栅栏
2017-11-04 16:54
295 查看
1082: [SCOI2005]栅栏
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2508 Solved: 1072
[Submit][Status][Discuss]
Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需
要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长
度为8和2的两个木板。你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰
最多能够得到多少他所需要的木板。
Input
第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板
的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。Sample Input
430
40
50
25
10
15
16
17
18
19
20
21
25
24
30
Sample Output
7HINT
25切出 21 30切出 20 40切出 19、18 50切出 15、16、17Source
[Submit][Status][Discuss]
花式搜索配合花式二分加上玄学剪枝
首先如果我们要切出x个木板,那么显然肯定是前x小的木板
所以我们将木材和木板都排好,二分x,dfs从大到小(因为从小到大枚举可能导致后面的木板没法切出来)枚举每一个木板从哪一个木材中切出来
加上两个剪枝
1、如果当前枚举的木板和上一个枚举的木板一样大,那么显然可以从上一层枚举的那个木材开始枚举
2、记没用的木材(即不能切出木板的木材)的和为rest,若rest与mid个木板的和大于所有的木材和,那么剪枝
代码:
#include<cstdio> #include<cmath> #include<queue> #include<stack> #include<vector> #include<algorithm> #include<cstring> using namespace std; typedef long long LL; const int INF = 2147483647; const int maxn = 1010; int n,m,a[maxn],s[maxn],c[maxn],b[maxn],minx,sum; inline LL getint() { LL ret = 0,f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return ret * f; } inline bool dfs(int dep,int rest,int pos,int tot) { if (rest + s[tot] > sum) return 0; if (!dep) return 1; for (int i = b[dep] == b[dep + 1] ? pos : 1; i <= n; i++) { if (a[i] < b[dep]) continue; if (a[i] - b[dep] < minx) rest += a[i] - b[dep]; a[i] -= b[dep]; if (dfs(dep - 1,rest,i,tot)) return 1; a[i] += b[dep]; if (a[i] - b[dep] < minx) rest -= a[i] - b[dep]; } return 0; } int main() { minx = INF; n = getint(); for (int i = 1; i <= n; i++) sum += c[i] = getint(); m = getint(); for (int i = 1; i <= m; i++) minx = min(minx,b[i] = getint()); sort(c + 1,c + n + 1); sort(b + 1,b + m + 1); for (int i = 1; i <= m; i++) s[i] = s[i - 1] + b[i]; int l = 0,r = m; while (r - l > 1) { int mid = l + r >> 1; for (int i = 1; i <= n; i++) a[i] = c[i]; if (dfs(mid,0,1,mid)) l = mid; else r = mid; } int ans = 0; for (int i = 1; i <= n; i++) a[i] = c[i]; if (dfs(r,0,1,r)) ans = r; else ans = l; printf("%d",ans); return 0; }
相关文章推荐
- bzoj 1082: [SCOI2005]栅栏 (二分+dfs)
- bzoj1082: [SCOI2005]栅栏
- BZOJ1082: [SCOI2005]栅栏
- [bzoj] 1082: [SCOI2005]栅栏
- bzoj1082[SCOI2005]栅栏
- bzoj 1082: [SCOI2005]栅栏【二分+dfs】
- BZOJ 1082: [SCOI2005]栅栏 DFS,剪枝,二分答案
- 【BZOJ 1082】[SCOI2005]栅栏 二分+dfs
- BZOJ1082 [SCOI2005]栅栏
- 【BZOJ】1082: [SCOI2005]栅栏(二分+dfs)
- 【bzoj1082】 SCOI2005—栅栏
- 【bzoj1082】 SCOI2005 栅栏 二分+搜索
- [bzoj1082][SCOI2005]栅栏(二分+dfs剪枝)
- [BZOJ1082][SCOI2005]栅栏 二分+搜索减枝
- 【BZOJ 1082】 [SCOI2005]栅栏
- BZOJ 1082: [SCOI2005]栅栏|二分答案爆搜
- bzoj 1082: [SCOI2005]栅栏
- BZOJ1082: [SCOI2005]栅栏
- BZOJ 1082 【SCOI2005】 栅栏
- BZOJ1082: [SCOI2005]栅栏