DP经典问题:多米诺骨牌(TYVJ 2199, COGS 1205)
来源:互联网 发布:软件改变生活 编辑:程序博客网 时间:2024/06/08 09:06
这道题算是一个经典的DP问题,它可以用背包来写,因为我们知道数据范围是1000,而且,多米诺骨牌的点数是1到6,所以上下之差最多是5000,所以写个背包复杂度上限是O(1k*5k)。
状态f[i][j]表示前i个数,总和达到j时翻的最小牌数。决策同背包,只有两种:翻与不翻,所以方程就是f[i][j] = min(f[i-1][j-a[i]], f[i-1][j+a[i]] + 1), a[i]表示的是第i个骨牌上下之差(在这里,骨牌的点数没有什么用,所以我们保存的是上下之差。。或下上只差。)。
需要注意的是,C++并没有负下标。所以j需要稍微转化一下,原本j的范围是-5k ~ 5k,把它变成0~1w即可,不过要注意的是,只需要在赋初值f[1][a[1]]与f[1][-a[1]]需要分别在其后加上5*n (注意不是5k,5k是最大数据范围,即n=1k时才加5k)。
求出f数组后就可以找答案了,注意在f数组在赋初值之前要memset一下,设为无穷大。找答案的过程从f[n][j]中找,令j=5*n,因为5*n的实际意义是和为0,之后寻找j+i与j-i,i = 0~5*n,直到找到min(f[n][j+i], f[n][j-i])不是正无穷,这就表示可以达到上下和之差最小为j+i或j-i,输出最小值即可。
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int n, sum, a[1005], f[1005][10005];int abs(int x) {return x > 0 ? x : -x;}int main(){ memset(f, 0x7f, sizeof f); scanf("%d", &n); for(int i = 1; i <= n; i++){ int t1, t2; scanf("%d %d", &t1, &t2); a[i] = t1 - t2; } f[1][a[1]+5*n] = 0; f[1][-a[1]+5*n] = 1; for(int i = 2; i <= n; i++) for(int j = abs(a[i]); j <= 10*n; j++) f[i][j] = min(f[i-1][j-a[i]], f[i-1][j+a[i]]+1); for(int i = 0; i <= 5*n; i++){ int t = min(f[n][5*n+i], f[n][5*n-i]); if(t < 1005) {printf("%d", t); break;} } }
0 0
- DP经典问题:多米诺骨牌(TYVJ 2199, COGS 1205)
- [Tyvj 2199]多米诺骨牌
- poj2411 2663 2420 dp+状态压缩(多米诺骨牌问题)
- poj2411 2663 2420 dp+状态压缩(多米诺骨牌问题)
- 轮廓线DP(插头DP 裸 经典骨牌)
- poj 2411 骨牌覆盖问题 状压dp
- 骨牌问题(DP+矩阵快速幂)
- Tyvj P1016 装箱问题 (DP)
- Tyvj P1059 过河问题 - DP&状态压缩
- 【DP】17.2.7 T3 多米诺骨牌 题解
- [背包DP] [Luogu P1282] 多米诺骨牌
- 洛谷 P1282 多米诺骨牌 (背包dp)
- [Poj1717]&[洛谷1282]多米诺骨牌 背包Dp
- [POJ1717][luogu1282]Dominoes(多米诺骨牌)(dp)
- COGS 498 TYVJ 1094 矩形分割 贪心
- Cogs 876. 游戏(DP)
- 邮局--dp经典问题
- 【DP经典问题】WordBreak
- poj 2481(树状数组)
- 1505: 酷酷的单词
- 黑马程序员———多线程和死锁问题总结
- NEUQ 1420: Problem A - Y2K Accounting Bug
- Knowledge Generation Model for Visual Analytics
- DP经典问题:多米诺骨牌(TYVJ 2199, COGS 1205)
- 奋斗假分页
- JS登陆与注册验证
- C++对象模型——解构语意学(第五章)
- kafka0.8.2以下版本删除topic
- 深度学习文献阅读笔记(2)
- Andorid ListView和Adapter优化
- melody
- [持续更新]JavaScript学习笔记(四)