
ACM_动态规划
羁绊残阳
四川大学计算机科学与技术
展开
-
hdu 2602 01背包深入优化
背景:没有认真读题目条件,搞错输入顺序而wa了一次。自己做的第一道DP题,看了好久终于把背包九讲的01背包看懂了。学习:1.01背包的特点是:物品个数有限,切对于每一个物品可以选择放或者不放。其中的名称01,大概就是1(放)0(不放)的意思吧。 传统的背包写法使用二维数组,时间和空间都是O(VN),当把j由0.....n,换为n.....0之后空间优化为O(V),然后做了两点剪枝,原创 2015-02-08 22:34:03 · 542 阅读 · 0 评论 -
hdu 1171 01背包变形
背景:1Y对于背包写法,不太熟,想法也不够深,写起来,容易犯小错误。思路:把sum/2当做背包的最大容量,求这个最大容量能够装下的最大价值,这个题的灵活之处就是把价值和体积都看做题中给的价值,那么相当于,一份体积有一份价值。所以sum/2的体积产生的价值势必小于等于sum/2,这样我们求出这个最接近sum/2的值即可。这个题的思路比较巧妙,一是把看似两方面的问题转化为单方面要接近一半的问题原创 2015-02-10 10:58:09 · 673 阅读 · 0 评论 -
hdu 2546 01背包
背景:1——WA:卡上最低要求为5元才能消费的边界情况没有处理。思路:首先判断卡上余额是否有五元,不是直接输出。然后,从卡里面拿出五元来买最大价值,剩下的钱尽可能用完就可以了。学习:1.这里透露了一个基本问题:从n个数中选取m个数,使这m个数的和尽可能的接近k。这个体是把k看做背包的容量,把一个数的值既看做价值又看做体积,转化为01背包问题。我的代码:#include#include原创 2015-02-10 11:45:33 · 509 阅读 · 0 评论 -
hdu 3127 完全背包 二维限制条件 放置顺序相关性
背景:这个题实在没法,看的题解的思路,确实很难想到。也算明白了背包问题只是母题,其生的儿子,往往找不出来原来的母亲了。思路:我的代码:#include#include#includeusing namespace std;int F[1009][1009],w[10][3];int main(void){ int t,n,x,y; scanf("%d",&t原创 2015-03-04 23:57:17 · 731 阅读 · 0 评论 -
hdu 2159 二维完全背包
背景:二维数组为限制条件的完全背包,1Y。思路:转移方程:F[i][j]=max{F[i][j],F[i-1][j-C[k]+W[k]},F[i][j]为在i为最大人数为i,最大忍耐度为j的情况下所能达到的最大经验值。一旦经验值达到目标要求经验值,就记录当前罪恶值,找出所有大到经验要求罪恶值中的最小罪恶值即可。学习:进化仍然是转移方程的确立,背包类问题,按照模型进行变换就好。找到限制条件和原创 2015-03-06 16:25:47 · 582 阅读 · 0 评论 -
hdu 2844 多重背包
背景:主要是理解了二进制的应用。下次写背包九应该把代码模板化一点了,避免错误。思路:F[i]=mas{F[i-kC[i]]+kW[i] | 0 =学习:1.价值和花费都是本身的值得情况,可以用来判断这些数是否可以组成另一个数。#include#include#includeusing namespace std;int c[109][2],F[100009];int main原创 2015-03-07 21:14:01 · 670 阅读 · 0 评论 -
hdu 2159 01背包
背景:01背包,开始尽然忘了01背包的内循环是倒着来的=_=我的代码:#include#include#includeusing namespace std;int c[10009];double w[10009],F[10009];int main(void){ int n,m; while(scanf("%d%d",&n,&m) && n*n+m*m){原创 2015-03-06 16:34:17 · 601 阅读 · 0 评论 -
hdu 2191 多重背包,自己写模板
背景:wa了几次,都是小失误:把i--写成i++之类的,写的时候一定要想到具体用意。还有就是一定要至少写三组测试数据!!!!!!!学习:模板化写多重背包。#include#include#includeusing namespace std;int t,v,n;int c[109],w[109],num[109],F[109];void zeroonebag(int cost,i原创 2015-03-07 22:00:01 · 631 阅读 · 0 评论 -
hdu 1712 分组背包
背景:1Y,01背包多加了一个挑选循环而已。分组背包的典型描述:对于很多背包,把它分为k个组,每个组内的组员是相互冲突的,所以只能选择一个。我的代码:#include#include#includeusing namespace std;int main(void){ int n,m; while(scanf("%d%d",&n,&m),n*n+m*m){原创 2015-03-08 22:20:57 · 540 阅读 · 0 评论 -
hdu 3535 经典混合分组背包
背景:难!!不看解题报告是绝对想不到。即使看了解题报告的思路再去裸写也有很多误区。。。。#include#include#includeusing namespace std;int F[109][109],n,v,cost[109],weight[109],ith;void free(void){ //make the zeroonebag choose to each t原创 2015-03-11 22:34:29 · 540 阅读 · 0 评论 -
hdu 3449 有依赖的背包
背景:1——TL按照背包九讲的把没一个依赖组转用01背包转化成物品集合,然后又用分组背包的方法来做,超时。优化无果,借鉴别人思路ac。正确写法思路:先不管必须选盒子这个前提,按照01背包的思想把物品选一次到thing[]数组中,然后再把再强项对每个数据都买盒子,这样thing中只有thing[box....v]能买起盒子,且thing[k]=thing[k-box]+0 ,盒子的价值是0.所以原创 2015-03-14 14:07:28 · 883 阅读 · 0 评论 -
hdu 1159 经典dp最长公共子序列
背景:上次比赛就没有做出来,回来根据实际意义半天也想不出如何dp,结果从猜转移方程入手,竟然想对了!开始想把空间优化到一维数组,没有想到要用同维度左边的值wa了。思路:dp[i][j]=max{max[i-1][j],max[i][j-1],max[i-1][j-1]+(a[i] == b[j])}//dp[i][j]定以为,a串的前i个字符和b串的前b个字符的最大字串和,为选a串的第i原创 2015-04-10 22:37:00 · 574 阅读 · 0 评论 -
挑战程序设计竞赛 多重部分和问题(恰好装满的完全背包)
这里一般的完全背包做法:转化为01背包(可以对01背包进行二进制优化),复杂度是O(n∗V∗logV/cost[i]2)O(n*V*log^{V/cost[i]}_2)。 这里巧妙的定义了一种方法让复杂度降到了O(n∗V)O(n*V) **转移方程思想:定义能装满dp[i][j]为容量为j时,第i种物品的剩余个数,则: if (dp[i-1][j] >= 0),dp[i][j]=m原创 2015-04-11 15:12:17 · 1114 阅读 · 2 评论 -
挑战程序设计竞赛 01背包变换对象
01背包式最简单的背包问题,书上是由深度优先搜索的记忆化搜索的递归实现到处递推的解决方法就是01背包,把所有i和j的情况都记下来,总共不过n*v种情况。 而01背包之2是简单01背包变换对象之后的做法。 题目描述如下: 有n个价值和花费分别为weight[i]和cost[i]的物品,把这些物品装进容量为V的背包中,求最大价值? 但是现在条件是:V<=109,weight[i]<100,n<1原创 2015-04-11 13:50:37 · 996 阅读 · 0 评论 -
soj 2222 01背包变形
背景:wa~Tl~看来背包还是很欠缺啊~思路1(1500ms):变形的01背包。把题目改为:选择一组HP和大于等于所需血量且这组物品的分数之和最小,即可。这里把HP看做cost,score看做weight。但是这个题有个特点是最后选择HP必须大于等于k,容易想到,最多我们会有k+10000(10000为单个物品的最大HP值)的HP值,所以我们有这样的转移方程:for i 0....n原创 2015-04-07 16:17:54 · 544 阅读 · 0 评论 -
poj 2533 最长上升子序列
背景:最长上升字串,自己想了好久,想出了O(n2)O(n^2)的方法,书上写有O(nlogn)O(nlogn)的方法。#include #include #include #include using namespace std;const int M = 1009, INF = 0x3fffffff;int main(void) { int n, str[1009],原创 2015-04-14 17:24:10 · 448 阅读 · 0 评论 -
挑战程序设计竞赛 划分数,贝尔数,斯特灵数
斯特灵数:把nn个数划分为恰好kk个非空集合的个数,记为S(n,k)S(n, k)。且有:S(n,1)=S(n,n)=1S(n, 1) = S(n, n) = 1。 有递推关系式:S(n+1,k)=S(n,k−1)+kS(n,k−1)S(n + 1, k) = S(n, k - 1) + kS(n, k - 1) 贝儿数:把nn个数划分为非空集合的所有划分数。有:Bn=∑i=0nS(n,i)Bn原创 2015-04-17 11:01:04 · 874 阅读 · 0 评论 -
hdu 1422 环状最大非负子段
题意:一个列数,构成环形,找出其中满足每走一步都大于等于0的子段的最大长度解法:类似环形都是用两个数组相接的方式来实现的,不过看了别人代码发现没有必要,多开一倍空间,直接对下标进行取余操作就可以达到理想效果。我是枚举环的起点(从0到n - 1),然后每个起点开始的长度为n的序列,用类似最大连续子串和的方法求出其最大子串长度,这样复杂度是O(n2)O(n^2)有更好的思路:自己把这两倍长度的原创 2015-05-10 22:01:47 · 600 阅读 · 0 评论 -
soj 4421 最长回文子序列
题意:给你一个字符串,求该字符串的最长回文子序列长度。解法:以前做过连续最长回文子串的长度就是通过构造奇数偶数长度的来做,而本题是不连续。注意到回文字符串的特点是从左边向右边看和从右边向左边看是一样的效果,那么就可以把目标字符串s导致后产生一个t,子串中如果t和s相同那么这个子串就是回文子串,那么就转化为这两个子串求LCS(longest common subsequent)的问题了。我的原创 2015-05-17 12:54:57 · 603 阅读 · 0 评论 -
poj 2089 数位DP
题意:给你一个区间,求这个区间内所有满足不含数字2,不含连续数字62的数字的个数。(本题核心思想见代码注解)题并非水,然而大部分人还是水过的,对1到10,000,000内数字转化为字符串打表处理即可水过。然而做这个题主要是为了掌握数位DP。数位DP常见知识点:求区间[l, r]之间的数常常转化为求区间[0 ,r] - [0, l]之间的数,因为l,r上界下界并不好做。数位DP的核心就是无后效原创 2015-05-30 22:46:03 · 760 阅读 · 0 评论 -
hdu 1160 排序 + 最长上升子序列
题意:输出体重上升而速度下降的最长子序列题意:先按照结构体升序排序体重,之后用dp对速度求最长下降子序列即可。代码:#include <set>#include <map>#include <cmath>#include <stack>#include <queue>#include <string>#include <vector>#include <cstdio>#inc原创 2015-05-24 08:48:52 · 801 阅读 · 0 评论 -
codeforces 161D Distance in Tree (树形DP 经典题)
题意:给你一颗树,和一个数k,问树中长度为k的路径的条数.分析:一看就是树形DP的类型.树形DP的特点就是用所有叶子节点的信息更新出其父亲节点,然后这些父亲节点再作为叶子节点,这样层层递归直到根节点. 这里很容易想到的一种叶子节点更新父亲节点的方式如下: 定义dp[i][j]dp[i][j]为节点i为根的所有子树中长度为j的路径的条数. 那么就容易有:dp[i][j]=∑u(u为i的所有原创 2015-08-31 15:57:51 · 985 阅读 · 0 评论 -
Codeforces Round #274 (Div. 2) E:Riding in a Lift DP + 前缀优化
题意: n,a,b,k(2 ≤ n ≤ 5000,1 ≤ k ≤ 5000,1 ≤ a, b ≤ n,a ≠ b).n, a, b, k (2 ≤ n ≤ 5000, 1 ≤ k ≤ 5000, 1 ≤ a, b ≤ n, a ≠ b).四个数.1到n的数,顺序排列,其实位置人在a位置而中心位置在b,人每次只能走一个点走动的距离必须小于|b−a||b - a|,人走k步之后停止,问人一共有多少种走原创 2015-08-17 22:06:30 · 596 阅读 · 0 评论 -
Codeforces 295 B Greg and Graph (Floyd_Warshall的深入理解)
@(K ACMer)By题解工厂题意分析Code题意:给你一个有向图,图中任意两点间皆有两个方向的两条边.并给定一个序列,按照序列顺序删除图中的顶点,问每次删除一个顶点之前图中所有两点间的最短距离为多少.分析:想到任意两点间的最短距离首先想到的就是Floyd_Warshall算法.要做这个题需要深入理解该算法的思想. 先看原始的算法实现:void floydwarshall(void){原创 2015-09-03 21:54:49 · 657 阅读 · 0 评论 -
Codeforces 156C (DP)
[TOC] @(K ACMer) by 题解工厂题意:给你一个小写字母构成的序列,序列内支持相邻的字符进行ASCII码迁移操作(即一个ASCII码加x,另一个就减x).问该序列可以变换为多少种其它不同的序列.分析:典型的种类计数问题,容易想到要用DP.但是直接想是不容易想到的.需要观察迁移操作的特点是整个序列的ASCII码始终是不变的. 定义:dp[i][j]为长度为i,ASCII值为j的序列原创 2015-09-09 00:12:13 · 487 阅读 · 0 评论 -
Codeforces 567C Geometric Progression (离散 + DP)
@(K ACMer) by 题解工厂题意:给你一个序列,求序列中长度为3的公比为k的子序列的个数.分析:典型的情况数量问题,一看就应该想到用DP去解决,不难想到一个数xx为结尾的长度为i的子序列等于,以它前面的数x/kx/k结尾的长度为i-1的子序列数. 定义:dp[i][j] 以j结尾的长度为i的子序列的个数 有转移方程dp[i][j]=dp[i−1][j/k]dp[i][j] = dp原创 2015-09-05 14:04:10 · 767 阅读 · 1 评论 -
hdu 5418 (状态压缩DP)
@(k ACMer) by 题解工厂题意:裸的TSP问题,这里就不再赘述啦*^*分析:这里主要是探讨一下状态压缩DP的思想,相比于一般的DP我们都是定义dp[i][j]dp[i][j],其中的i和j往往是以xx结尾的,长度为xx的意识,他们都有一个具体的内涵.而在TSP问题中,我们找不到一个具体的内涵来赋给下标,只能用一个集合ss来表示,哪些点走过,哪些点没有走过.这种把集合用一个整数的二进制表达来原创 2015-09-12 18:38:28 · 471 阅读 · 0 评论 -
soj 2978 Tasks
@(K ACMer) 题意 数组a全部为0,给你一个和数组a同样大小的数组b,你可以选择把任意一个a[i]a[i]变成b[i]b[i].但是保证必须保证a中所有元素的和小于t. 定义f(a)为a数组中最长的连续0的个数,求f(a)的最小值. 分析: 看起来这个题,要直接求出来最优结果似乎是不可能的,最暴力的枚举是2的指数次的显然不可行. 我们可以二分的来枚举这个最长区间的长度k.然后去判原创 2015-11-04 14:25:46 · 394 阅读 · 0 评论 -
soj 2113 数字游戏(环形DP)
@(K ACMer)题意: 给你一个长度为n的环,你要把它划分为m个部分,让每个部分内部元素的和取余10再相乘得到的字尽可能大(小). 分析: 如果题中是把一个链划分为m部分,显然可以用dp的方法,定义dp[i][j]dp[i][j]为前i个数划分为j个部分的最大(小)值,那么可以有转移方程:dp[i][j]=max(dp[i][j],dp[k][j−1]∗((sum[i]−sum[k])dp原创 2015-11-05 20:43:46 · 577 阅读 · 0 评论 -
soj 1685: Chopsticks(线性dp)
@(K ACMer)题意: 给你n个人,你需要给(n+8)(n + 8)个人,每个人发三只筷子.这三只筷子中较小两个长度的差值的平方就是这三只筷子的差异值.要求把k根筷子分发给(n+8)(n + 8)个人,让总的差异值最小. 分析: 首先拿到这个问题,会发现要选一定选择相邻的两个作为筷子的性质.因为只有它们的差值最小. 那我们先不考虑第三根筷子,可以很直观的想到一个dp,定义dp[i][j]原创 2015-11-06 02:49:49 · 528 阅读 · 0 评论 -
soj 1162: I-Keyboard(dp + 记忆化搜索)
@(K ACMer)题意: 手机有k个按键,你有l个字符需要印在这些按键上,每个字符被使用的平均频率已知.要求设计出一个最佳的按键分块方案,使期望的按次数最小. 分析: 就是把l个字符划分为k分,让每一份的按键次数加起来最小,典型的划分dp. 定义dp[i][j]dp[i][j]为把前i个数划分为j个部分的最小期望按的次数总和.那么有转移方程: dp[i][j]=min(dp[k][j−1原创 2015-11-07 20:15:41 · 559 阅读 · 0 评论 -
soj 2505: The County Fair(离散化 + 记忆化搜索)
@(K ACMer) 题意 有n个展台,你初始时刻在1号展台,时间为0.然后每个展台都会在一个固定的时间p(i)(0<p(i)<1e9)p(i)(0 < p(i) < 1e9)发奖品,从起点出发,你能前往任何展台,但是必须在该点等到p(i)时间拿到奖品,然后再离开,从每两个展台相互之间的转移需要时间T(i,j)T(i,j).问你最多可以得到多少个奖品. (注:这里除了没有必要在第一个展台待到它原创 2015-11-06 14:31:10 · 377 阅读 · 0 评论 -
soj 2785 Binary Partitions (构造类似完全背包)
@(K ACMer)题意: 给你一个数n,求它的二进制表达有多少种? (注意两个二进制表达的元素是相同的,则认为他们是相同的,与顺序无关)我们假设n等于5,来观察一下暴力的解法. 首先5个1肯定是最简单地表达方式:1+1+1+1+11 + 1+1 + 1+ 1它的种数显然为1. 然后最右边的两个1可以合并为2,即:1+1+1+21 + 1 + 1 + 2 然后:1+2+21 + 2 + 2原创 2015-10-23 07:50:41 · 473 阅读 · 0 评论 -
soj 3596 Article Decryption(trie树 + dp)
@(K ACMer)题意: 给你一些单词,和一个长字符串s,s是由这些单词组成的,总共有多少种组成的可能? 分析: 问有多少种可能显然的dp,很容易的想到定义dp[i]dp[i]为s前i个字符形成的字符串最多有多少种可能,则有转移方程:dp[i]=∑j=0i−1isword(j+1,i) ? dp[j] : 0dp[i] = \sum _{j = 0}^{i - 1} isword(j +原创 2015-11-08 16:29:07 · 429 阅读 · 0 评论 -
SOJ 2818 QQ音速 (DP)
@(K ACMer)题意: 给你一个数n,求它的二进制表达有多少种? (注意两个二进制表达的元素是相同的,则认为他们是相同的,与顺序无关)我们假设n等于5,来观察一下暴力的解法. 首先5个1肯定是最简单地表达方式:1+1+1+1+11 + 1+1 + 1+ 1它的种数显然为1. 然后最右边的两个1可以合并为2,即:1+1+1+21 + 1 + 1 + 2 然后:1+2+21 + 2 + 2原创 2015-10-23 07:51:28 · 663 阅读 · 0 评论 -
soj 2111: littleken bg
@(K ACMer)水得一发的01背包.#include <iostream>#include <cstdio>#include <cstring>#include <set>#include <map>#include <stack>#include <vector>#include <string>#include <queue>#include <cstdlib>#incl原创 2015-11-08 20:57:04 · 798 阅读 · 0 评论 -
soj 2142: Cow Exhibition(01背包的变形)
@(K ACMer)题意: 有n个物品,他们有两个属性,聪明值和有趣值,选择他们中的一些物品让聪明值和有趣值的和最大且聪明值或者有趣值的和不能为负数. 分析: 这个问题的精华在于讲原问题,转化为等价问题:dp[i]dp[i]表示聪明值为i时有趣值的最大值.最后再来扫描整个数组,求满足条件的即可. 转移方程如下: dp[i]=max(dp[i],dp[i−s[j]]+f[j])dp[i] =原创 2015-11-11 17:43:31 · 480 阅读 · 0 评论 -
soj 2800 三角形(DP)
题意 给你一个大三角形,黑色的是被减去的,白色的是剩下的,问剩下的白色区域中,最大的倒三角形是?分析: 看到这个题,首先想一下暴力,恩..可以搞,稳定超时. 然后我们需要去找如何DP了么… 那么是不是可以用直观的记忆化搜索呢?….想了一下,好像并不是很直观… 只有强行dp了么,找一找把当前的问题,分解为前面一个阶段的多个状态的子问题决定的. 那么我们定义以点(i,j)(i, j)为顶点的原创 2015-10-28 16:22:43 · 452 阅读 · 0 评论 -
soj 3360 Buying hay (完全背包)
题意: 有n个物品,每个物品都是无限制多个.具有价值和花费.你需要购买总价值至少为t的物品,而且它们的花费最小. 分析: 裸的恰好装满的完全背包之上多了,必须要大于等于最大容量,只需对转移方程式稍加变形即可.#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace原创 2015-10-28 17:15:24 · 420 阅读 · 0 评论 -
soj 3172 Fisherman (01背包的装满)
题意: 给你n个数,求可以用这些数组合出来的数的种数?(组合方式是加法). 分析: 对于恰好装满的01背包,最后的dp数组中元素只要不为INF,都可以被组合出来.统计不为INF的数的个数就可以了.#include <cstdio>#include <cstring>const int maxn = (1e6 + 9) * 2, INF = 0x3fffffff, mod = 1e6;typ原创 2015-10-28 17:17:10 · 411 阅读 · 0 评论