Codeforces 689 C The Values You Can Make(dp)
2016-07-08 16:11
519 查看
题意:
给你一些硬币,让你选出一个子集的总价值和为k,然后对于一个选出的子集,除了可以组成k以外,还可以在选出的子集中选出一些其他的价值。问你所有的选出的子集一共可以得到多少种价值。
对于这个,因为tag是动态规划,所以就往上面思考,但是找不到一个一个可行的状态。看过题解才明白,一个很机智的状态。
dp[i][j][k]表示前i个硬币组成了价值为j的一个子集并且里面可以得到k大小面额的情况是否存在。那么对于一个硬币,总共有三个转移,1、这个硬币避灾选出的子集中;2、这个硬币在选出的子集中但是不在拿出的子集中即子集的子集;3、这个硬币在所有的集合中。
所以dp[i][j][k]=dp[i−1][j][k]‖dp[i−1][j−c[i][k]‖dp[i−1][j−c[i]][k−c[i]]。我们在得到这个之后,既可以去尝试每一个可能的值是否存在。具体看代码。
代码:
给你一些硬币,让你选出一个子集的总价值和为k,然后对于一个选出的子集,除了可以组成k以外,还可以在选出的子集中选出一些其他的价值。问你所有的选出的子集一共可以得到多少种价值。
对于这个,因为tag是动态规划,所以就往上面思考,但是找不到一个一个可行的状态。看过题解才明白,一个很机智的状态。
dp[i][j][k]表示前i个硬币组成了价值为j的一个子集并且里面可以得到k大小面额的情况是否存在。那么对于一个硬币,总共有三个转移,1、这个硬币避灾选出的子集中;2、这个硬币在选出的子集中但是不在拿出的子集中即子集的子集;3、这个硬币在所有的集合中。
所以dp[i][j][k]=dp[i−1][j][k]‖dp[i−1][j−c[i][k]‖dp[i−1][j−c[i]][k−c[i]]。我们在得到这个之后,既可以去尝试每一个可能的值是否存在。具体看代码。
代码:
// // Created by CQU_CST_WuErli // Copyright (c) 2016 CQU_CST_WuErli. All rights reserved. // //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <cctype> #include <cmath> #include <string> #include <vector> #include <map> #include <queue> #include <stack> #include <set> #include <algorithm> #include <sstream> #define CLR(x) memset(x,0,sizeof(x)) #define OFF(x) memset(x,-1,sizeof(x)) #define MEM(x,a) memset((x),(a),sizeof(x)) #define BUG cout << "I am here" << endl #define lookln(x) cout << #x << "=" << x << endl #define SI(a) scanf("%d", &a) #define SII(a,b) scanf("%d%d", &a, &b) #define SIII(a,b,c) scanf("%d%d%d", &a, &b, &c) const int INF_INT=0x3f3f3f3f; const long long INF_LL=0x7f7f7f7f; const int MOD=1e9+7; const double eps=1e-10; const double pi=acos(-1); typedef long long ll; using namespace std; int n, k; int c[550]; int dp[2][555][555]; int main(int argc, char const *argv[]) { #ifdef LOCAL freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin); // freopen("C:\\Users\\john\\Desktop\\out.txt","w",stdout); #endif while (SII(n, k) == 2) { for (int i = 1; i <= n; i++) SI(c[i]); CLR(dp); dp[0][0][0] = 1; for (int i = 1; i <= n; i++) { int now = i % 2; int last = now ^ 1; for (int j = 0; j <= k; j++) { for (int s = 0; s <= j; s++) { dp[now][j][s] |= dp[last][j][s]; if (j >= c[i]) dp[now][j][s] |= dp[last][j - c[i]][s]; if (s >= c[i]) dp[now][j][s] |= dp[last][j - c[i]][s - c[i]]; } } } vector<int> ans; for (int i = 0; i <= k; i++) if (dp[n % 2][k][i]) ans.push_back(i); cout << (int)ans.size() << endl; for (int i = 0; i < ans.size(); i++) cout << ans[i] << ' '; cout << endl; } return 0; } /* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \| |// `. / \||| : |||// \ / _||||| -:- |||||- \ | | \\ - /// | | | \_| ''\---/'' | | \ .-\__ `-` ___/-. / ___`. .' /--.--\ `. . __ ."" '< `.___\_<|>_/___.' >'"". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `-. \_ __\ /__ _/ .-` / / ======`-.____`-.___\_____/___.-`____.-'====== `=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 佛祖保佑 永无BUG */
相关文章推荐
- C++动态规划之最长公子序列实例
- C++动态规划之背包问题解决方法
- C#使用动态规划解决0-1背包问题实例分析
- 详解Android应用中屏幕尺寸的获取及dp和px值的转换
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- 动态规划
- Android dpi,dip,dp的概念以及屏幕适配
- C++ 动态规划
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- 动态规划解决背包问题的核心思路
- DP(动态规划) 解游轮费用问题
- Android对px和dip进行尺寸转换的方法
- 动态规划的用法——01背包问题
- 动态规划的用法——01背包问题
- 《收集苹果》 动态规划入门