【CodeVS 1014】装箱问题
2016-11-06 17:21
309 查看
题目描述
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30),每个物品有一个体积(正整数)。要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
分析
思路1:判定性dp
设f[i][j]表示用了前n个物品,能否达到容量j。然后对f[n][j]=1取最大的j就可以了。
思路2:偏离搜索
我们有种很好的思想:贪心。先排序,然后每次尽可能取最大的。
但是这样是错误的。
我们考虑调整。
我们坚定几乎都是取最大的。
所以使用偏离搜索:只有限定次数能不取最大的。
结合一个剪枝:若之后的sum+当前的s<=v,则直接取完。
#include <cstdio> #include <cctype> #include <algorithm> using namespace std; #define rep(i,a,b) for (int i=(a);i<=(b);i++) const int N=32; const int D=5; int v,n; int a ; int sum ; int res; inline int rd(void) { int x=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } void DFS(int w,int del,int s) { if (s+sum[w]<=v) { res=max(res,s+sum[w]); return; } if (s+a[w]<=v) { DFS(w-1,del,s+a[w]); if (del<D) DFS(w-1,del+1,s); } else DFS(w-1,del,s); } int main(void) { freopen("codevs1014.in","r",stdin); freopen("codevs1014.out","w",stdout); v=rd(),n=rd(); rep(i,1,n) a[i]=rd(); sort(a+1,a+n+1); rep(i,1,n) sum[i]=sum[i-1]+a[i]; DFS(n,0,0); printf("%d\n",v-res); return 0; }
思路3:随机化
我们有种很好的思想:贪心。先排序,然后每次尽可能取最大的。
但是这样是错误的。
我们考虑不排序了。
多次随机序列,然后能取就取。
随机1000000次即可。
#include <cstdio> #include <cctype> #include <climits> #include <algorithm> using namespace std; #define rep(i,a,b) for (int i=(a);i<=(b);i++) #define per(i,a,b) for (int i=(a);i>=(b);i--) const int N=32; const int T=1000000; const int MAX=INT_MAX; int v,n; int a ; int res; inline int rd(void) { int x=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } int Calc(void) { int nv=0; rep(i,1,n) if (nv+a[i]<=v) nv+=a[i]; return v-nv; } int main(void) { // freopen("codevs1014.in","r",stdin); // freopen("codevs1014.out","w",stdout); v=rd(),n=rd(); rep(i,1,n) a[i]=rd(); res=MAX; rep(tms,1,T) { random_shuffle(a+1,a+n+1); int t=Calc(); res=min(res,t); } printf("%d\n",res); return 0; }
小结
(1)伪判定性问题我们称“是不是”这种问题为判定性问题。
而很多最值问题都可以通过判定性问题来表述,所以称这类问题为伪判定性的。
总之:许多判定性问题可以转化为最值问题。
(2)骗分的思路
骗分要有思路才行。
常规的骗分被称为“老实的骗分”,常见dfs求解,再结合两个常见的剪枝:①ans>=sum ②now+rest<=v
但是,有时候我们假如能想到一些错误的贪心,那么就可以诞生一些很棒的方法。常见方法1:偏离搜索。常见方法2:随机排列顺序,这种方法可用于最大团的求解。
总之,要活学活用,具体题目还是要具体分析。
相关文章推荐
- CODEVS 1014装箱问题
- Codevs1014 装箱问题
- 【codevs 1014】装箱问题
- 背包型动态规划练习-codevs-1014装箱问题
- Codevs 1014 装箱问题
- codeVS 1014 装箱问题 2001年NOIP全国联赛普及组
- 【codevs】1014 装箱问题
- 【动态规划】【零一背包】CODEVS 1014 装箱问题 2001年NOIP全国联赛普及组
- 1014 装箱问题
- codevs1014 装箱问题(DP)
- 【wikioi】1014 装箱问题
- WIKIOI-1014 装箱问题
- wikioi 1014 装箱问题 (2001年NOIP全国联赛普及组)
- [CODEVS1014]装箱问题
- 天梯 1014 装箱问题
- 【日常学习】【背包DP】codevs1014 装箱问题题解
- codevs1014 装箱问题(DP)
- wikioi-天梯-普及一等-背包dp-1014:装箱问题
- wikioi-1014 装箱问题
- wikioi天梯之1014 装箱问题 入门动态规划 【背包问题】