多维背包问题,不能用dp,因为n <= 50,所以剪枝搜索可以处理,对于每个rail,枚举它是从哪个board截取的,从一下几个方面剪枝即可
1)对rail和board排序,对于不同长度的rail,一定是取长度小的rail比较划算,所以我们取前k个rail处理
这里 sum(rail,k) <= sum(board) 并且 sum(rail,k+1) > sum(board)
2)充分利用题目条件:因为每个rail最长只有128,而rail可能会有1000,所以肯定有很多rail的长度相等,对于这些rail,我们只需要枚举一个下界即可,这样可以免
去很多重复的搜索
3)按照答案的要求搜索:按照rail的个数从多到少搜索,则第一次搜索到结果即可输出
4)设board之和是sum_board,n个rail之和sum_rail, 则最多只能浪费 sum_board - sum_rail 这么多木材,因为如果浪费更多的话,则剩余board肯定不够切
- #include <iostream>
- #include <algorithm>
- using namespace std;
- /*
- PROG: fence8
- LANG: C++
- ID: heben991
- */
- const int B = 60, R = 1100, L = 130;
- int board[B], rail[R], nboard, nrail;
- int remain[B], from[R], f[R], lim[R], board_sum, rail_sum;
- int ans, waste_max;
- void dfs(int k, int waste)
- {
- if(k < 0)
- {
- printf("%d/n", ans+1);
- exit(0);
- }
- int i;
- if(k != ans && rail[k] == rail[k+1]) i = from[k+1];
- else i = 0;
- for(; i < nboard; ++i)
- if(remain[i] >= rail[k])
- {
- from[k] = i;
- remain[i] -= rail[k];
- if(remain[i] < rail[0]) waste += remain[i];
- if(waste > waste_max)
- {
- waste -= remain[i]; //hint
- remain[i] += rail[k];
- continue;
- }
- dfs(k-1,waste);
- remain[i] += rail[k];
- }
- }
- int main()
- {
- int i, j, k, t;
- freopen("fence8.in", "r", stdin);
- freopen("fence8.out","w",stdout);
- scanf("%d", &nboard);
- board_sum = 0;
- for(i = 0; i < nboard; ++i)
- {
- scanf("%d", board+i);
- board_sum += board[i];
- }
- sort(board,board+nboard);
- for(i = 0; i < nboard; ++i) remain[i] = board[i];
- scanf("%d", &nrail);
- for(i = 0; i < nrail; ++i)
- {
- scanf("%d", rail+i);
- }
- sort(rail,rail+nrail);
- for(i = 0; i < nrail; ++i)
- {
- if(rail_sum + rail[i] > board_sum) break;
- rail_sum += rail[i];
- }
- nrail = i;
- for(i = nrail-1; i >= 0; --i)
- {
- ans = i;
- waste_max = board_sum - rail_sum;
- rail_sum -= rail[i];
- dfs(i,0);
- }
- puts("0");
- return 0;
- }