usaco4.12Fence Rails(迭代加深)
2013-08-28 19:36
141 查看
为了这题还去学了下迭代加深 回来还是不会写
只好参考各大神的代码及题解了
二分枚举最大可以切的块数 然后就是各种分析及优化
USACO题解里写了7个优化。。
我采用的是dfsid搜索每一个rail来源的board。以下技巧都是针对这种搜索顺序来制定的。 (注:rail是所需要切成的东西,board是供应商提供的原料)
如果使用dancing links的话,可以让程序的常数快2倍。
经过一些实验可以发现,先切大的rail比先切小的rail更容易提前出解。同样,[先切小的board比先切大的board更容易提前出解?]{注:好像先切大的board要比先切小的更快}。{*我的程序先切小再切大第5个点就TLE了,而先切大再切小就快很多,见C++程序.{跟我一样,握个手,一定要先大后小!!!}}
由于r最大可能是1023,但是rail长度的范围却只有0~128,这点提醒了我们有很多rail的长度会是相同的。所以我们要避免冗余,优化搜索顺序。若有rail[i+1]=rail[i],则rail[i+1]对应的board一定大于等于rail[i]对应的board。可以通过这种方法剪掉很多冗余的枝条。
相应的,如果board[i]=board[i+1],那么从board[i]切下的最大的rail一定大于等于从board[i+1]切下的最大的rail。
对于切剩下的board(无法再切下rail),统计一下总和。如果这个值大于board长度的总和减去rail长度的总和,一定无解,可以剪枝。这个剪枝最关键。
二分答案
其实在读入的过程中,如果rail[i] > max{board} 那么这个rail应该舍去 By Clarkok
View Code
只好参考各大神的代码及题解了
二分枚举最大可以切的块数 然后就是各种分析及优化
USACO题解里写了7个优化。。
问题分析
抽象一下就可以发现,算法的本质是多重背包问题。 补充:这题与破锣乐队都是多个背包,不可重复放物品。区别在于破锣乐队要有顺序,此题不需要,这样此题就必须要搜索才行。 单个背包的问题我们可以用DP解决,但是对于这种问题我们只能用搜索了。 但是可以看一看这道题的数据规模:1<=n<=50,1<=r<=1023。如此大的规模我们只能考虑进一步的优化。我采用的是dfsid搜索每一个rail来源的board。以下技巧都是针对这种搜索顺序来制定的。 (注:rail是所需要切成的东西,board是供应商提供的原料)
如果使用dancing links的话,可以让程序的常数快2倍。
优化技巧
很容易就能注意到,由于每块rail的价值是相等的——也就是说切小的要比切大的来的划算。那么我们在搜索能否切出i个rail的方案是自然要选最小的i个rail来切。经过一些实验可以发现,先切大的rail比先切小的rail更容易提前出解。同样,[先切小的board比先切大的board更容易提前出解?]{注:好像先切大的board要比先切小的更快}。{*我的程序先切小再切大第5个点就TLE了,而先切大再切小就快很多,见C++程序.{跟我一样,握个手,一定要先大后小!!!}}
由于r最大可能是1023,但是rail长度的范围却只有0~128,这点提醒了我们有很多rail的长度会是相同的。所以我们要避免冗余,优化搜索顺序。若有rail[i+1]=rail[i],则rail[i+1]对应的board一定大于等于rail[i]对应的board。可以通过这种方法剪掉很多冗余的枝条。
相应的,如果board[i]=board[i+1],那么从board[i]切下的最大的rail一定大于等于从board[i+1]切下的最大的rail。
对于切剩下的board(无法再切下rail),统计一下总和。如果这个值大于board长度的总和减去rail长度的总和,一定无解,可以剪枝。这个剪枝最关键。
二分答案
其实在读入的过程中,如果rail[i] > max{board} 那么这个rail应该舍去 By Clarkok
/* ID: shangca2 LANG: C++ TASK: fence8 */ #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<stdlib.h> using namespace std; int bo[55],te[55],ra[1050],v; int n,m,res,s,sum[1050],flag; void dfs(int tt,int st) { int i; if(flag) return ; if(tt==0)//全部可以切完 { flag = 1; return ; } int ss=0,o; for(i = 1 ; i <= n ; i++)//当前木板剩余值已经大于最多的剩余值 肯定不用再搜 { if(te[i]<ra[1]) ss+=te[i]; } if(ss>v) return ; for(i = st ; i <= n ; i++) { if(te[i]>=ra[tt]) { if(tt-1>=1&&ra[tt]==ra[tt-1])//一个小优化 如果ra[tt]已经在i~N里搜了 那么前面跟它相等的 就不会在i之前搜了 o = i; else o = 1; te[i]-=ra[tt]; dfs(tt-1,o); te[i]+=ra[tt]; } } return ; } int main() { //freopen("fence8.in","r",stdin); //freopen("fence8.out","w",stdout); int i; cin>>n; for(i = 1 ; i <= n ; i++) { scanf("%d",&bo[i]); s+=bo[i]; } sort(bo+1,bo+n+1); for(i = 1; i <= n ; i++) te[i] = bo[i]; scanf("%d",&m); for(i = 1; i <= m ; i++) { scanf("%d",&ra[i]); } sort(ra+1,ra+m+1); for(i = 1; i <= m ; i++) sum[i] = sum[i-1]+ra[i]; int low=0,high = m; while(low<high)//二分找一下 满足最多可以切多少块 { int mm = (low+high+1)>>1; v = s-sum[mm]; flag = 0; dfs(mm,1); if(flag) low = mm; else high = mm-1; } printf("%d\n",low); return 0; }
View Code
相关文章推荐
- UVA1343(The rotation Game|旋转游戏)=》状态空间分析+迭代加深搜
- HDU1560(迭代加深搜索)
- uva1374 快速幂计算 迭代加深优先逼近
- hdu 1667 /poj 2286 The Rotation Game(经典迭代加深)
- UVa 12558 Egyptian Fractions (HARD version)--迭代加深搜索
- 迭代加深搜索[codevs1004 四子连棋]
- 埃及分数-迭代加深
- 埃及分数 迭代加深搜索 IDA*
- C#实现八数码的IDEA*(迭代加深A*)算法
- 迭代加深搜索--埃及分数
- 习题7-7:埃及分数(迭代加深)
- codevs 1004 四子连棋 迭代加深搜索
- 【SCOI2005】骑士精神(Knight)(DFS+迭代加深)
- 迭代加深搜索IDA*---uva1343 the rotation game
- UVa 529 - Addition Chains ,迭代加深搜索+减枝
- poj1872A Dicey Problem(迭代加深dfs)
- POJ 3134 - Power Calculus 迭代加深搜索(DFSID)
- POJ 1753 Flip Game (迭代加深dfs 版本)
- 2286 The Rotation Game (1,状压 2,迭代加深搜索)
- UVa 11214 - Guarding the Chessboard(迭代加深搜索)