状态压缩DP 题目目录
2010-08-07 23:33
344 查看
POJ 1170
IOI95的题目了,比较简单。题目大意是说要买一些商品,而商店提供了一些组合购买的打折方案,你不能多买东西,问怎样购买最省。怎样表示状态呢?其实很自然想到把当前你要买哪些东西,并且它们分别要买多少作为状态,那么方程就写成:
F(S)=min[for each i in 合法购买方案](F(S’)+cost(i)]
现在的问题就成了如何在实现的时候来表示S。由于只买5种不同商品,每种的数量最多为5件,于是考虑用6进制表示状态,其中权位及表示商品种类,系数就是商品数量,然后再把这个数压缩成一个10进制数,于是在程序中就好处理了。
这样每次转移时先把该状态还原成六进制,然后转移后再压缩即可。时间为O(m*k*6^n),空间O(6^n)。
没用到状态压缩,题目就是用node表示一种方案,把所有方案都存起来,再对方案进行0-1背包式的放入,选择最优解!事实上那个5维数组可以用状态来表示
POJ 1691
这题看起来复杂,其实就是要你找到一种表示当前棋盘状态的方法。由于只有15个方块,很自然又想到了二进制表示,第k位为0表示第k块矩形已经作色,为1就还没有。还有先预处理一个有向图,s->t表示t在s的上方,于是每次转移的时候枚举颜色,然后看一次最多能涂多少(可以证明每次都贪心尽量涂是最好的策略),递归处理就好了。
POJ 1185
NOI01的题目,相当经典的问题。这题其实和CEOI的bugs integreted inc是一样的,同时和上面第一题的方法也一样,就是用三进制来表示当前位置的状态,0表示这格安放炮兵,1表示上面一格有,2表示上面两格有,这样上下的情况就解决了,转移时再枚举一下邻里的情况就可以。还要注意使用滚动数组优化空间,时间O(n*2^m*3^m),空间O(3^m)。
最后再来说下关于实现的问题。
最常用和直接的方法就是记忆化搜索,非常容易实现,传递压缩后的状态即可。当状态规模小,而转移又比较多并且是二进制压缩时时,还可以使用迭代状态空间的办法(iterative through the state space),就是枚举每种组合,然后转移。
IOI95的题目了,比较简单。题目大意是说要买一些商品,而商店提供了一些组合购买的打折方案,你不能多买东西,问怎样购买最省。怎样表示状态呢?其实很自然想到把当前你要买哪些东西,并且它们分别要买多少作为状态,那么方程就写成:
F(S)=min[for each i in 合法购买方案](F(S’)+cost(i)]
现在的问题就成了如何在实现的时候来表示S。由于只买5种不同商品,每种的数量最多为5件,于是考虑用6进制表示状态,其中权位及表示商品种类,系数就是商品数量,然后再把这个数压缩成一个10进制数,于是在程序中就好处理了。
这样每次转移时先把该状态还原成六进制,然后转移后再压缩即可。时间为O(m*k*6^n),空间O(6^n)。
没用到状态压缩,题目就是用node表示一种方案,把所有方案都存起来,再对方案进行0-1背包式的放入,选择最优解!事实上那个5维数组可以用状态来表示
]#include <iostream> using namespace std; int b,s; int dp[6][6][6][6][6]; struct node {//一种销售方案 int n[6]; //各个物品卖多少个 int sum; //该方案的价值 }; node ideal[200]; int code[1000]; int num[10]; void Init() { int c,k,p,n; int i,j; memset(ideal,0,sizeof(ideal)); // scanf("%d",&b); for(i=1;i<=b;i++) { scanf("%d%d%d",&c,&num[i],&p); code[c] = i; ideal[i].n[i] = 1; ideal[i].sum = p; } scanf("%d",&s); for(i=1;i<=s;i++) { scanf("%d",&n); for(j=1;j<=n;j++) { scanf("%d%d",&c,&k); ideal[b+i].n[code[c]] = k; } scanf("%d",&p); ideal[b+i].sum = p; } } int getnum(int x1,int x2,int x3,int x4,int x5) { int i; if(dp[x1][x2][x3][x4][x5] > -1) { return dp[x1][x2][x3][x4][x5]; } int min = 0x7fffffff; for(i=1;i<=s+b;i++) { if(x1>=ideal[i].n[1] && x2>=ideal[i].n[2] && x3>=ideal[i].n[3] && x4>=ideal[i].n[4] && x5>=ideal[i].n[5]) { int temp = ideal[i].sum + getnum(x1-ideal[i].n[1],x2-ideal[i].n[2],x3-ideal[i].n[3],x4-ideal[i].n[4],x5-ideal[i].n[5]); if(temp < min) min = temp; } } dp[x1][x2][x3][x4][x5] = min; return min; } int main() { while(scanf("%d",&b)!=EOF) { Init(); memset(dp,-1,sizeof(dp)); dp[0][0][0][0][0] = 0; int numm = getnum(num[1],num[2],num[3],num[4],num[5]); printf("%d/n",numm); } return 0; }
POJ 1691
这题看起来复杂,其实就是要你找到一种表示当前棋盘状态的方法。由于只有15个方块,很自然又想到了二进制表示,第k位为0表示第k块矩形已经作色,为1就还没有。还有先预处理一个有向图,s->t表示t在s的上方,于是每次转移的时候枚举颜色,然后看一次最多能涂多少(可以证明每次都贪心尽量涂是最好的策略),递归处理就好了。
POJ 1185
NOI01的题目,相当经典的问题。这题其实和CEOI的bugs integreted inc是一样的,同时和上面第一题的方法也一样,就是用三进制来表示当前位置的状态,0表示这格安放炮兵,1表示上面一格有,2表示上面两格有,这样上下的情况就解决了,转移时再枚举一下邻里的情况就可以。还要注意使用滚动数组优化空间,时间O(n*2^m*3^m),空间O(3^m)。
最后再来说下关于实现的问题。
最常用和直接的方法就是记忆化搜索,非常容易实现,传递压缩后的状态即可。当状态规模小,而转移又比较多并且是二进制压缩时时,还可以使用迭代状态空间的办法(iterative through the state space),就是枚举每种组合,然后转移。
相关文章推荐
- 状态压缩DP题目专辑
- 九度OJ 9月赛第二场 题目1542:黑白迷阵 (状态压缩DP)
- 状态压缩dp题目
- 状态压缩DP 题目小节 (一)
- BZOJ题目1087: [SCOI2005]互不侵犯King(状态压缩DP)
- hdu 2167 状态压缩dp(入门题目)
- hdu 3811 用状态压缩DP 解决看似组合数学的题目
- 状态压缩DP题目小节(三)
- ZOJ 题目3777 Problem Arrangement(状态压缩DP)
- 状态压缩dp入门题目
- 状态压缩dp入门题目总结——炮兵阵地和TSP问题
- 状态压缩DP题目小节(二)
- 状态压缩DP题目小节(二)
- 状态压缩DP 题目小节 (一)
- fzuoj 2218 Simple String Problem(状态压缩dp)
- POJ 1038 Bugs Integrated, Inc. 状态压缩DP
- poj 2411 Mondriaan's Dream(状态压缩dp)
- poj 2923(状态压缩dp)
- Corn Fields POJ - 3254 状态压缩dp入门
- uva 10817 - Headmaster's Headache ( 状态压缩dp)