usaco6.3.1 Fence Rails

17 篇文章 0 订阅

一 原题

Fence Rails
Burch, Kolstad, and Schrijvers

Farmer John is trying to erect a fence around part of his field. He has decided on the shape of the fence and has even already installed the posts, but he's having a problem with the rails. The local lumber store has dropped off boards of varying lengths; Farmer John must create as many of the rails he needs from the supplied boards.

Of course, Farmer John can cut the boards, so a 9 foot board can be cut into a 5 foot rail and a 4 foot rail (or three 3 foot rails, etc.). Farmer John has an `ideal saw', so ignore the `kerf' (distance lost during sawing); presume that perfect cuts can be made.

The lengths required for the rails might or might not include duplicates (e.g., a three foot rail and also another three foot rail might both be required). There is no need to manufacture more rails (or more of any kind of rail) than called for the list of required rails.

PROGRAM NAME: fence8

INPUT FORMAT

Line 1:N (1 <= N <= 50), the number of boards
Line 2..N+1:N lines, each containing a single integer that represents the length of one supplied board
Line N+2:R (1 <= R <= 1023), the number of rails
Line N+3..N+R+1:R lines, each containing a single integer (1 <= ri <= 128) that represents the length of a single required fence rail

SAMPLE INPUT (file fence8.in)

4
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30

OUTPUT FORMAT

A single integer on a line that is the total number of fence rails that can be cut from the supplied boards. Of course, it might not be possible to cut all the possible rails from the given boards.

SAMPLE OUTPUT (file fence8.out)

7


二 分析

二分搜索答案+DFS。因为只关心最多能得到多少个rail,所以我们尽量选择那些短的rail,因此第一步是对rail从小到大排序。在检验k是否为一个可行解时,等价于判断能否裁剪出前k小的rail。检验过程是DFS,需要剪枝,比较强的剪枝有两个:
1. 如果上一个rail被安排在了第k根board上,并且当前rail长度和上一个rail长度相等(建立在排序的基础上),那么当前rail从第k根board开始检验是否可以安排下。(最强力的剪枝
2. 用boardsum代表所有board的长度和,用railsum[n]代表最小的n个rail长度和。放下最小的k个rail最多只能浪费boardsum-railsum[k],记为maxwaste,在搜索过程中记录一下当前已经浪费掉的长度(如果一根board剩余的长度小于rail[0]的长度,可以视为浪费掉了)curwaste,一旦curwaste>maxwaste,就可以认定这次搜索失败了。


三 代码

运行结果:
USER: Qi Shen [maxkibb3]
TASK: fence8
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 4192 KB]
   Test 2: TEST OK [0.000 secs, 4192 KB]
   Test 3: TEST OK [0.000 secs, 4192 KB]
   Test 4: TEST OK [0.000 secs, 4192 KB]
   Test 5: TEST OK [0.000 secs, 4192 KB]
   Test 6: TEST OK [0.000 secs, 4192 KB]
   Test 7: TEST OK [0.000 secs, 4192 KB]
   Test 8: TEST OK [0.000 secs, 4192 KB]
   Test 9: TEST OK [0.000 secs, 4192 KB]
   Test 10: TEST OK [0.000 secs, 4192 KB]
   Test 11: TEST OK [0.000 secs, 4192 KB]
   Test 12: TEST OK [0.000 secs, 4192 KB]

All tests OK.

Your program ('fence8') produced all correct answers! This is your submission #3 for this problem. Congratulations!


AC代码:
/*
ID:maxkibb3
LANG:C++
PROB:fence8
*/

#include<cstdio>
#include<algorithm>

const int MAX_BOARD = 55;
const int MAX_RAIL = 1024;

int n, m, board[MAX_BOARD], rail[MAX_RAIL];
int boardsum, railsum[MAX_RAIL];
int curwaste, maxwaste, cutfrom[MAX_RAIL];

void init() {
	scanf("%d", &n);
	for(int i = 0; i < n; i++) {
		scanf("%d", &board[i]);
		boardsum += board[i];
	}
	scanf("%d", &m);
	for(int i = 0; i < m; i++)
		scanf("%d", &rail[i]);
	std::sort(rail, rail + m);
	railsum[0] = rail[0];
	for(int i = 1; i < m; i++)
		railsum[i] = railsum[i - 1] + rail[i];
}

bool dfs(int index) {
	if(curwaste > maxwaste) return false;
	if(index < 0) return true;
	int st = 0;
	if(rail[index] == rail[index + 1])
		st = cutfrom[index + 1];
	for(int i = st; i < n; i++) {
		if(board[i] < rail[index]) continue;
		board[i] -= rail[index];
		cutfrom[index] = i;
		if(board[i] < rail[0]) curwaste += board[i];
		bool flag = dfs(index - 1);
		if(board[i] < rail[0]) curwaste -= board[i];
		cutfrom[index] = 0;
		board[i] += rail[index];
		if(flag) return true;
	}
	return false;
}

void solve() {
	int l = 0, r = m;
	while(l < r) {
		int mid = l + ((r - l + 1) >> 1);
		maxwaste = boardsum - railsum[mid - 1];
		if(dfs(mid - 1)) l = mid;
		else r = mid - 1;
	}
	printf("%d\n", l);
}

int main() {
	freopen("fence8.in", "r", stdin);
	freopen("fence8.out", "w", stdout);
	init();
	solve();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值