随笔分类 - { 动态规划 }
摘要:题目大概是依次有n场派对,每场派对都有需要穿某套衣服去参加,可以同时穿多套衣服,就是一套套着一套,如果脱了的话就不能再穿上那套了,问最少需要几套衣服去参加完所有派对。 区间DP: dp[i][j]第i场到第j场派对需要最少的衣服 dp[i][i]=1 dp[i][j]=min(dp[i][j-1]+
阅读全文
摘要:题目给定一个字符串集合有几种方式拼成一个字符串。 dp[i]表示stri...strlen-1的方案数 dp[len]=1 dp[i]=∑dp[j](stri...strj-1∈SET) 用集合的字符串构造一棵Trie树,然后就可以在线性时间判断哪几个前缀字符串在集合里。 1 #include<cs
阅读全文
摘要:题目大概是,二进制数可以看作是由几段连续的0和连续的1组成,问:n位没有前导0的 且 共用k段连续0/1组成的 且 连续0/1个数不超过m的二进制数有多少个。 用dp[n][k][m]表示问题 dp[i][1][j]=1 (i<=j) 通过枚举第一段连续数字的个数first,使dp[n][k][m]
阅读全文
摘要:题目大概就是求一个n个不同的数能构造出几种形态的二叉排序树。 和另一道经典题目n个结点二叉树不同形态的数量一个递推解法,其实这两个问题的解都是是卡特兰数。 dp[n]表示用n个数的方案数 转移就枚举第几个数作为根,然后分成左右两子树,左右两子树的方案数的乘积就是这个数作根的方案数 另外就是题目得先找
阅读全文
摘要:一道经典的树型DP入门题。dp[u][0/1]表示u点不选或选时以u为根的子树最多能选择的点数。 题目给的有向有环图可以看作森林,注意不是树,因为题目没有说图是连通的! 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 us
阅读全文
摘要:题目大概是说给一棵树的n个结点从1到n编号,要求每个结点的编号大于其父结点,问有多少种编号方式。 想了挺久的,感觉有点眉目,最后画了下样例YY出解法: 首先求出以每个结点为根的子树大小,记为size[u],这个DFS一遍就可以求出来; 接下来,dp[u]表示给以u为根的子树size[u]个编号有几种
阅读全文
摘要:题目问N匹马比赛有多少种结果。一开始想用排列组合搞搞,然后发现想错了。艰难地把思路转向DP,最后AC了。 dp[i][j]表示前i匹马确定出j个名次的方案数 dp[1][1]=1 对于第i匹马,它要确定出j个名次:要嘛前i-1匹确定出j个次名,然后第i匹可以成为第1...j名;要嘛前i-1匹确定出j
阅读全文
摘要:题目问从N个数中取出M个数,有多少种取法使它们的和能被D整除。 dp[i][j][k]表示,前i个数取出j个数模D的余数为k的方案数 我用“我为人人”的方式来转移,就从i到i+1转移,对于第i+1个数有取和不取两种选择,然后确定j和k这两个维度的情况。 另外题目说数字是32位有符号整数,所以是会出现
阅读全文
摘要:dp[S]表示已经完成的工作集合 枚举从哪儿转移过来的,再通过枚举计算花费。。水水的。。 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 #define INF (1<<30)
阅读全文
摘要:题目要求第k个没有连续两个1的二进制数。 这算数位DP吧,只不过以前遇到的是统计区间的数字情况,而这题是求第几个数字,差不多是反过来的。 本来我想用状态dp[i][0/1]表示长度i末尾0或1的二进制数个数,发现这样好像没法解。 最后需要根据数位DP状态的值推算出要求二进制数各个位置是0还是1,这个
阅读全文
摘要:这题要求区间有多少个模K且各位数之和模K都等于0的数字。 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解。 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k
阅读全文
摘要:第一眼以为是概率DP,我还不会。不过看题目那么短就读读,其实这应该还不是概率DP,只是个水水的DP。。 dp[n][s]表示掷n次骰子点数和为s的情况数 dp[0][0]=1 dp[i][j]=∑dp[i-1][j-k] (k∈[1,6] 且 j-k>=0) 要求的概率就是情况数/掷n次骰子的总情况
阅读全文
摘要:dp[i][j]表示长度i末尾为S[j]的方案数 dp[1][0...m-1]=1 dp[i][j]=∑dp[i-1][k] (|S[k]-S[j]|<=2) 1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 using nam
阅读全文
摘要:这道题可以想到几点: 整个行程可以看作一次次的行走,每次行走都是用最短的路程从某一非空点到达另外一非空点; 两点间最少的步数是二者x和y坐标差的最大值; 返回原点这个过程,肯定是取完最后一个黄金后直接用最少的步数从这儿出发回到原点。 然后就是状压DP了: dp[u][S]:经过非空点集S后到达u点最
阅读全文
摘要:这题感觉做法应该挺多吧,数据规模那么小。 我用DP乱搞了。。 dp0[i][j]表示字符串前i位能否组成末尾有连续j个元音字母 dp1[i][j]表示字符串前i位能否组成末尾有连续j个辅音字母 我的转移方案是尽量不要出现BAD字符串。 如果最后转移不过去那就说明一定会出现BAD字符串,如果可以转移到
阅读全文
摘要:问题问的是最少可以把一个字符串分成几段,使每段都是回文串。 一开始想直接区间DP,dp[i][j]表示子串[i,j]的答案,不过字符串长度1000,100W个状态,一个状态从多个状态转移来的,转移的时候要枚举,这样时间复杂度是不可行的。 然后我就想降维度了,只能线性DP,dp[i]表示子串[0,i]
阅读全文
摘要:dp[S]表示已经消灭目标集合为S的最少射击数 dp[0]=0 dp[S]=min( dp[S'] + min( health[i] , health[i]/demage[j][i] ) ) 其中S-S'={i},j∈S' 1 #include<cstdio> 2 #include<cstring>
阅读全文
摘要:题目要计算一个字符串最少添加几个字符使其成为回文串。 一年多前,我LCS这道经典DP例题看得还一知半解时遇到一样的问题,http://acm.fafu.edu.cn/problem.php?id=1007。 当时完全靠自己瞎YY出了LCS的解法: 我当时这么想的: 把字符串分成两个部分,假设这两个部
阅读全文
摘要:显然数位DP。 dp[i][j]表示所有末尾为j的i位二进制数相邻位的数量和 初始状态dp[2][1]=1 从长度i-1转移到长度i就是在i-1位的末尾添上0或1,转移方程就是: dp[i][0]=dp[i-1][0]+dp[i-1][1] dp[i][1]=dp[i-1][0]+dp[i-1][1
阅读全文
摘要:我可能真想不到这题是区间DP,不过知道是区间DP想了下就AC了。 dp[i][j]表示局面为ai...aj先手能获得与后手得分的最大差值 那么转移到当前状态就是枚举中间的位置,分成两边,其中一边先手全部取另一边就是新的局面,后手变成新的先手的局面,而后手也会采取最优策略也会尽量让剩下这个局面差值最大
阅读全文