USACO Section 4.1 Fence Rails(DFSID)
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
HINTS (use them carefully!)
题意:给你 n 个木块,需要 m 个木板,问切割这 n 个木块,最多可以切割多少木板。
分析:由于答案可以很确定上下界,故二分答案,然后DFS判断是否可以切割。思想类似(DFSID)。
现在分析两个细节问题怎样DFS和怎样减枝。
怎样DFS:DFS的作用是给定木块数 k ,判断是否可以切割,这 k 个木块很明显使用最小的 k 个木块,对于每个木块任何比其大的木板都要考虑是否来它;
怎样减枝:我使用了三个减枝
第一:枚举木块是从大到小;
第二:由于木块的重复量很多,所以对于相同的木块和木板判断是否可以切割时只需判断一遍;
第三:浪费的木板,DFS判断是有个最大浪费量,如果DFS途中浪费量大于最大浪费量时直接跳出。
/* ID: dizzy_l1 LANG: C++ TASK: fence8 */ #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define MAXN 51 #define MAXM 1024 using namespace std; int n,m,sum_board,waste,twaste; int board[MAXN],rail[MAXM],sum_rail[MAXM],tboard[MAXN]; bool DFS(int p,int q)//p、q分别表示考虑第 p 木块,来自从第 q 块木板开始的 { int i; if(p<=0) return true; if(waste<twaste) return false; for(i=q;i<=n;i++) { if(tboard[i]>=rail[p]) { tboard[i]-=rail[p]; if(tboard[i]<rail[1]) twaste+=tboard[i];//减枝三 if(rail[p]==rail[p-1])//减枝二 { if(DFS(p-1,i)) return true; } else { if(DFS(p-1,1)) return true; } if(tboard[i]<rail[1]) twaste-=tboard[i]; tboard[i]+=rail[p]; } } return false; } int DFSID() { int L,Mid,R,i; L=1;R=m; while(L<=R)//二分枚举答案 { for(i=1;i<=n;i++) tboard[i]=board[i]; Mid=(L+R)>>1; waste=sum_board-sum_rail[Mid]; twaste=0; if(DFS(Mid,1))//判断是否可以分割Mid块rail L=Mid+1; else R=Mid-1; } return R; } int main() { freopen("fence8.in","r",stdin); freopen("fence8.out","w",stdout); int i; while(scanf("%d",&n)==1) { memset(board,0,sizeof(board)); memset(rail,0,sizeof(rail)); memset(sum_rail,0,sizeof(sum_rail)); sum_board=0; for(i=1;i<=n;i++) { scanf("%d",board+i); sum_board+=board[i]; } scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d",rail+i); } sort(board+1,board+n+1); sort(rail+1,rail+m+1); for(i=1;i<=m;i++) { sum_rail[i]=sum_rail[i-1]+rail[i]; if(sum_board<sum_rail[i]) break; } m=i-1; printf("%d\n",DFSID()); } return 0; }