随笔分类 -  动态规划

摘要:题目:伐木工人用电锯伐木,一共需要砍n棵树,每棵树的高度为a[i],每次砍伐只能砍1单位高度,之后需要对电锯进行充电,费用为当前砍掉的树中最大id的b[id]值。a[1] = 1 , b[n] = 0,a[i]b[i+1]。问砍完所有的树的最小费用。分析:由于b[n] = 0 , 所以很容易弄出一个O(n^2)的状态转移方程。dp[1] = 0;for(int i=2;i#include #include #include #include #include #include #include #include #include #include #include using namespac 阅读全文
posted @ 2013-10-01 10:56 yejinru 阅读(450) 评论(0) 推荐(0) 编辑
摘要:335B - Palindrome题目: 给出一个字符串(均有小写字母组成),如果有长度为100的回文子串,输出该子串。否则输出最长的回文子串。分析: 虽然输入串的长度比较长,但是如果存在单个字母100或以上的话,直接输出即可。 利用抽屉原理发现,如果不存在上面所说的情况,长度不会超过26*99 dp[l][r]表示l到r的回文子串的长度,dp转移方式比较明显,记录一下得到最优值时的位置。 输出方案时,如果dp[1][len]>=100的话,显然可以输出长度100的子串,否则直接输出该长度。 具体实现用到了栈、队列保存信息,可以看代码。#include #include #incl... 阅读全文
posted @ 2013-09-15 22:37 yejinru 阅读(260) 评论(0) 推荐(0) 编辑
摘要:这里有状态压缩DP的好博文题目:题目比较神,自己看题目吧分析:大概有两种思路:1.dfs,判断正方形的话可以通过枚举对角线,大概每次减少4个三角形,加上一些小剪枝的话可以过。2.状压DP,先预处理出所有可以组成正方形的方案,根据题目的数据范围计算不会超过100个正方形方案。n个正方形用二进制的方式记录,每一位记录是否有没有引爆,则状态转移比较明显了。#include #include #include #include #include #include #include #include #include #include #include #include using namespace 阅读全文
posted @ 2013-09-15 20:55 yejinru 阅读(879) 评论(0) 推荐(0) 编辑
摘要:比赛时,开了大号去做,算了半天发现不会做A,囧。于是跑去看B,发现很水?于是很快敲完了,但是A不会,没敢交。于是去看C,一直找规律啊,后来总算调了出来,看了一下榜,发现还是算了吧,直接去睡觉了。第二天一起床把代码一交,居然A了,发现交的话rating还能涨一点,囧。B:其实就是求一个最长不下降子序列的长度。注意到数据范围,使用二分的方式求解。#include #include #include #include #include #include #include #include #include #include #include #include using namespace st.. 阅读全文
posted @ 2013-08-31 19:46 yejinru 阅读(328) 评论(0) 推荐(0) 编辑
摘要:1040: [ZJOI2008]骑士Time Limit:10 SecMemory Limit:162 MBSubmit:1190Solved:465[Submit][Status]DescriptionZ国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往 阅读全文
posted @ 2013-08-31 15:44 yejinru 阅读(383) 评论(0) 推荐(0) 编辑
摘要:題目: 有50斤的人c1人,100斤的人c2人。現在他們需要過河,但是只有一條船,並且船的載重重量不超過k。問有多少種方法 使得運人過河的次數最少。分析: 三維DP。 由於從河的對岸過來以及過去河的對岸是等價的,所以我們直接考慮單次過河的情況。 dp[i][x][y]表示第i次過河,過河之後對岸有50斤的人x,100斤的人y的方法數。 我們假設第n次過河的人的個數為i,j,過河前河岸有x,y人,所以過完河之後河的對岸有c1-x+i,c2-y+j人。 所以轉移方程為 dp[n][c1-x+i][c2-y+j] += dp[n-1][x][y]*comb[x][i]... 阅读全文
posted @ 2013-04-15 10:08 yejinru 阅读(213) 评论(0) 推荐(0) 编辑
摘要:題目:1055: [HAOI2008]玩具取名Time Limit:10 SecMemory Limit:162 MBSubmit:409Solved:255[Submit][Status][Discuss]Description某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。 现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。Input第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。 接下来W行,每 阅读全文
posted @ 2013-04-11 19:50 yejinru 阅读(387) 评论(0) 推荐(0) 编辑
摘要:题目: 给出一棵树,现要从树的1号节点走到n号节点,每条边都需要一定的时间才能走过,并且每个节点有相应的财宝,现在给出时间t,问能不能在时间t之内走到n节点且使得所获得的财宝最多(每个节点的财宝只能收集一次)分析: 先spfa算出1号节点走到n号节点所经过的节点,算出的最短路若不满足小于等于给定的时间t,要被饿死。在spfa中,用path数组记录每个节点的前驱以及该节点是从那条边过来的,走完之后,用n的前驱把该路上的边权全部更新为0,表示不用时间花费,再在深搜之前把总时间减掉他即为其他走过了两次的不在最短路径上面的节点所花费的时间总和。 树上背包的转移方程为 dp[x]... 阅读全文
posted @ 2012-09-09 11:15 yejinru 阅读(423) 评论(0) 推荐(0) 编辑
摘要:/*字符串DP,但是要找到用最小的字符串来匹配,所以用dp储存当前所使用过的字符串数。打印路径的话直接用数组表示前缀*/#include <iostream>#include <string>#include <cstring>#include <cstdio>using namespace std;string s = "22233344115566070778889990";#define X 50010int dp[X],pre[X],len[X],p[X],L;string a[X],in[X],b;void chan 阅读全文
posted @ 2012-04-30 16:01 yejinru 阅读(208) 评论(0) 推荐(0) 编辑
摘要:/*题目: 把石头分成两堆,问最小的重量差值为多少。分析: 先求和,然后用和的一半转为01背包。转移方程为: dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+w[i]); 缩小维度后为dp[j] = max(dp[j],dp[j-w[i]]+w[i]);*/#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int X = 2000010;int dp[X],w[25],n;int main(){ freopen(& 阅读全文
posted @ 2012-04-30 15:53 yejinru 阅读(228) 评论(0) 推荐(0) 编辑
摘要:/*分析: 由于有些物品存在多个,可以用数组逐一保存下,然后用01背包问题求解, 但是这样太耗时间,会造成time limitted,可以用二进制形式保存拥有多个 的物品,这样可以考虑完全并且比较省时间*/#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define X 100005int dp[X],cash[X];int main(){ freopen("poj1276.in","r",stdin); freope 阅读全文
posted @ 2012-03-20 14:45 yejinru 阅读(190) 评论(0) 推荐(0) 编辑
摘要:此方法是看了别人的题解的,利用像dp的思维做,f[m][n] = f[m][n-1]+f[m-n][n],其中f[m][n]表示m个水果n个盘子时总的放的方法数,因为f[m][n]总可以通过有空盘子或者没空盘子来放,f[m][n-1]表示有空盘子的情况,而f[m-n][n]表示没有空盘子的情况,思路非常巧妙#include <iostream>using namespace std;int ans;int dfs(int m,int n){ if(m==1) return 1; if(m<0) return 0; if(n==1) return 1; return dfs(m 阅读全文
posted @ 2012-03-20 14:33 yejinru 阅读(155) 评论(0) 推荐(0) 编辑
摘要:周赛的题目,思想011111111111000111111111111111转换为011111122222000333111444222555然后按该位置的高度向两边扩展,当遇到小于该高度时,停止扩展,然后用右边的下标减左边的下标加一,再乘以当前的高度即为所求,dp的实现是在计算第二个矩阵时用到的,只是简单的h[i,j] = h[i-1,j]+1 (map[i][j]=='F')#include <cstring>#include <iostream>#include <string>using namespace std;#define X 阅读全文
posted @ 2012-03-19 15:28 yejinru 阅读(169) 评论(0) 推荐(0) 编辑
摘要:输入括号输入:(注意:据说有空行,用getline()或者gets()输入)([(]([(((])))[]]]]])))(((要求输出最小要加入的括号数目之后的匹配括号串分析: 经典dp题,如果用dp自底向上的递推做的话,比较麻烦,其实用记忆化做很简单, 每次递归前加上判断是否已经计算过即可减少计算量,相当于dfs里的剪枝,代码如下#include <iostream>#include <string>#include <cstring>using namespace std;#define X 205#define INF 1000int dp[X][X] 阅读全文
posted @ 2012-03-19 11:13 yejinru 阅读(158) 评论(0) 推荐(1) 编辑
摘要:此题跟之前的括号最小添加数目一样的做法,只不过某些地方稍加改动,可以看看前一篇的括号最小添加数#include <iostream>#include <string>#include <cstring>using namespace std;#define X 210#define INF 1000string s;int dp[X][X];int f(int i,int j) //记忆化dp{ if(dp[i][j]!=-1) //如果已经算过,直接结束 return dp[i][j]; else if(i>=j) return 0; int ans 阅读全文
posted @ 2012-03-19 08:56 yejinru 阅读(117) 评论(0) 推荐(0) 编辑
摘要:题目:输入括号输入:(注意有空行,用getline()或者gets()输入)([(]([(((])))[]]]]])))(((要求输出最小要加入的括号数目分析: 经典dp题,如果用dp自底向上的递推做的话,比较麻烦,其实用记忆化做很简单, 每次递归前加上判断是否已经计算过即可减少计算量,相当于dfs里的剪枝,代码如下#include <iostream>#include <string>#include <cstring>using namespace std;#define X 205#define INF 1000int dp[X][X];string 阅读全文
posted @ 2012-03-19 08:32 yejinru 阅读(305) 评论(0) 推荐(0) 编辑
摘要:做完整数划分那题后,现在感觉这道题很简单,状态转移方程为dp[i][j] = dp[i][i] j>i = dp[i-j][j-1]+dp[i][j-1]建议看看我的博客上的hoj1402题#include <iostream>#include <cstring>using namespace std;#define X 510long long dp[X][X],n;void init(){ memset(dp,0,sizeof(dp)); for(int i=1;i<X;i++) //初始化 { dp[1][i] = 1; dp[0][i] = 1; } 阅读全文
posted @ 2012-03-13 21:17 yejinru 阅读(127) 评论(0) 推荐(0) 编辑
摘要:/*整数划分是一个经典的问题。希望这道题会对你的组合数学的解题能力有所帮助。Input 每组输入是两个整数n和k。(1 <= n <= 50, 1 <= k <= n)Output 对于每组输入,请输出六行。 第一行: 将n划分成若干正整数之和的划分数。 第二行: 将n划分成k个正整数之和的划分数。 第三行: 将n划分成最大数不超过k的划分数。 第四行: 将n划分成若干奇正整数之和的划分数。 第五行: 将n划分成若干不同整数之和的划分数。 第六行: 打印一个空行。第一行和第三行: 对于第一行和第三行,根据状态转移方程很容易写出: dp[i][j] = dp[i][i] 阅读全文
posted @ 2012-03-13 20:55 yejinru 阅读(373) 评论(0) 推荐(1) 编辑
摘要:题目: 求最长的重量上升且iq下降的子序列分析: 其实就是最长上升子序列的变形,其实很简单,先按重量按照由小到大进行排序, 然后就是LIS的事,打印路径的话,用数组path[]记录后面的位置,利用 递归实现打印(具体参考算法导论)#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define X 1005int dp[X],path[X];struct node{ int iq,w,id; //记录iq,重量 阅读全文
posted @ 2012-03-09 16:40 yejinru 阅读(239) 评论(0) 推荐(0) 编辑
摘要:题目:回文是一个对称的字符串,换句话说,这个字符串从左到右读和从右到左读是一样的。给出一个字符串,你要编一个程序,决定要插入的最少的字符个数,使得原字符串成为一个回文。比如,字符串”Ab3bd”中插入2个字符,使得它能变成一个回文("dAb3bAd" 或 "Adb3bdA")。如果插入少于2个字符,将无法产生回文。求最少插入几个字符,使其变成回文字符串分析:S1 = Ab3bd 的反转为S2 = db3ba要使S1变成回文字符串,可先求出S1,S2的最长公共子序列,用n-lcs(S1,S2)即可,本题转化为求S1,S2的最长公共子序列状态转移方程:if( 阅读全文
posted @ 2012-02-29 22:30 yejinru 阅读(213) 评论(0) 推荐(0) 编辑