POJ 3181 Dollar Dayz
2016-05-30 17:07
387 查看
题意:输入n、k,问将n用1~k这k个数字进行拆分,有多少种拆分方法。例如:n=5,k=3则有以下5种拆分方法:
n=3+2
n=3+1+1
n=2+1+1+1
n=2+2+1
n=1+1+1+1+1
此题是个背包问题,如果想不到可以将其看作是一个普通动态规划。
dp[i][j] 表示用i种价格配出金额j的方案数。
状态转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-i]+dp[i-1][j-2i]+dp[i-1][j-3j]…+dp[i-1][0]
状态转移方程就是将所有由i-1状态,通过添加k(=0,1,2…)个i可以到达dp[i][j]的状态的数字相加。如:dp[i-1][j]表示由i-1价格不需要添加i就可以到达金额j,dp[i-1][j-i]表示由i-1种价格需要再利用加个i且要添加1个价格i才能到达金额j,dp[i-1][j-2i]表示由i-1种价格需要再利用价格i且要添加2个i才能到达金额j,以此类推。
由于相加后得到的结果可能相当大,已经超过了long long,所以应该用大数。用两个unsigned long long 分别表示低位和高位,由于 unsigned long long 最大范围到
2^64-1即:18446744073709551615 ;所以取一个比这个值小一个数量级同时又能被10整除的数作为limit。
#include <iostream> using namespace std; unsigned long long b[105][1005], a[105][1005]; unsigned long long inf = 1; int main() { int n, k; cin >> n >> k; memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); for (int i = 0; i < 18; ++i) { inf *= 10; } a[0][0] = 1; //dp[i][j] = dp[i – 1][j] + dp[i – 1][j – i] + dp[i – 1][j – 2 * i] + … + dp[i – 1][0] for (int i = 1; i <= k; ++i) { for (int j = 0; j <= n; ++j) { for (int m = 0; m*i <= j; ++m) { b[i][j] = b[i][j] + b[i - 1][j - m*i] + (a[i][j] + a[i - 1][j - m*i]) / inf; a[i][j] = (a[i][j] + a[i - 1][j - m*i]) % inf; } } } if (b[k] ) { cout << b[k] ; } cout << a[k] << endl; return 0; }
提交之后是可以过的,结果如下:
看了大神的分析后,觉得自己的A题之路还有如此的遥远。
仔细考虑可以发现其实可以转到dp[i][j]的状态有两种:一种是dp[i-1][j]就是不用i这个数字拼接j这个数字的方法数,另一种是a[i][j-i]就是用了i这个数字拼接得到j-i的方法数。那么状态转移方程可以写为dp[i][j]=dp[i-1][j]+a[i][j-i]。
#include<iostream> using namespace std; long long a[105][1005], b[105][1005]; int main() { int n, k; cin >> n >> k; long long inf = 1; for (int i = 0; i < 18; ++i) { inf *= 10; } memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); for (int i = 0; i <= k; ++i) { a[i][0] = 1; } //dp[i][j]=dp[i-1][j]+dp[i][j-i]; for (int i = 1; i <= k; ++i) { for (int j = 1; j <= n; ++j) { if (i > j) { b[i][j] = b[i - 1][j]; a[i][j] = a[i - 1][j]; continue; } a[i][j] = (a[i - 1][j] + a[i][j - i]) % inf; b[i][j] = b[i - 1][j] + b[i][j - i] + (a[i - 1][j] + a[i][j - i]) / inf; } } if (b[k] ) { cout << b[k] ; } cout << a[k] << endl; return 0; }
相关文章推荐
- Leetcode 204. Count Primes
- Java 性能优化
- 强悍的 Linux —— 网络
- 简单Git服务器搭建
- OPatch Version: 11.2.0.3.13版本与OPatch Version: 11.2.0.3.10版本升级补丁区别
- 【BZOJ4145】[AMPPZ2014]The Prices【状压DP】【背包】
- Android的IPC机制(二)——AIDL实现原理简析
- 【Android Studio快捷键】之导入相应包声明(import packages)
- Android静默安装和静默卸载代码
- Qt之表单布局(QFormLayout)
- AlertDialog----确认单击物理键退出对话框
- WGS84、GCJ-02(火星坐标)、百度坐标,Web墨卡托坐标
- The Flash
- Hadoop实例:二度人脉与好友推荐
- 数据结构-链表
- 正则表达式
- Swift3.0发布过程
- Qt之表单布局(QFormLayout)
- poj3181 Dollar Dayz (DP+大数)
- Learning to Rank 简介