题目大意
给你n个木板,给你这些木板的长度,你可以把这些木板切开,现在有m个木料,问你最多可以切出多少个木料
解题思路
可以dfs枚举每个木料用哪个木板来切
但这样显然会超时,那么考虑剪枝
1.对于一些木板,连最小的木料都切不出来,那么显然不要
2.对于一些木料,脸最大的木板都无法切出它,那么也不要
3.切木板显然尽量切小的,因为可以切出大的那么肯定可以切出小的,对此可以二分答案,当一块木板剩余大小连最小的都切不了了,那么剩下的就浪费了,当浪费的大于木板总量减去二分的木料总量(剩下的不可能切出来),那么久退出
4.先用大的木块,先切大的木料
5.当有相同的木料时,所选木块编号不小于前一个
6.当最大木块可以切出若干最小木料时,二分左指针往右
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 1021
using namespace std;
int n, m, l, r, mw, mn, wst, mid, summ, a[50], b[N], sum[N];
bool dfs(int x, int lst)
{if (!x) return true;for (int i = b[x] == b[x + 1] ? lst : mn; i <= n; ++i)//相同的编号比上一个大{if (a[i] < b[x] || a[i] == a[i - 1]) continue;//木块相同就不再dfs了a[i] -= b[x];if (a[i] < b[1]){wst += a[i];//浪费的if (wst > mw){wst -= a[i];a[i] += b[x];continue;}}if (dfs(x - 1, i)){a[i] += b[x];return true;}if (a[i] < b[1])wst -= a[i];a[i] += b[x];}return false;
}
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 + 1 + n);sort(b + 1, b + 1 + m);mn = 1;for (int i = 1; i <= n; ++i)if (a[i] < b[1]) mn++;//最小的都切不出来else summ += a[i];for (int i = 1; i <= m; ++i){sum[i] = sum[i - 1] + b[i];if (b[i] > a[n] || sum[i] > summ){m = i - 1;//大于总值了break;}}l = 1;r = m;while(a[n] >= sum[l + 1]) l++;//最大的可以解决这些全部reverse(a + mn, a + n + 1);while(l < r){mid = (l + r + 1) >> 1;wst = 0;mw = summ - sum[mid];if (dfs(mid, mn)) l = mid;//二分else r = mid - 1;}printf("%d", l);return 0;
}