随笔分类 - DP(动态规划)
摘要:题意:略分析:记忆化搜索用dp[i][j] 表示 i 次攻击得到少于j分的方案hdu4504#include<iostream>#include<algorithm>#include<stdio.h>#include<stdlib.h>#include<string.h>using namespace std;const int N = 20 + 5;const int M = 600 + 10;__int64 f[N];__int64 dp[N][M];int s[3] = {1, 2, 3};void init(){ f[0] =
阅读全文
摘要:题意:忽略题目背景,就是要收集最多的钱, 如果第i天拿到了si 的钱, 那么第i+x[i] 天 到 第i + y[i] - 1 天必须再拿一次,否则就再也拿不到钱了,当然,第i +x[i]天之前也是拿不到的, 题目要求第一天必须拿。。分析:一开始想到了用记忆化搜索,代码很短, 一下就敲完了, 结果也果断超时了后来想到了按记忆化搜索的思路,直接从最后一天开始算起,用dp[i] 表示第i天拿到了钱之后,到第n天为止,最多拿到的钱数,那么dp[i] = s[i] + max(dp[j]) (i + x[i] <= j <= i + y[i] - 1)到这一步就很明显了,这里涉及到了区间最
阅读全文
摘要:题意:给定N 个字符串,每个字符串长度为小于等于10 ,要求得到一个排列,s[i] 为str[i] 和str[i - 1] 通过移动,相同位置上相同字符的个数,求max(s[1] + s[2] + s[3] +...)分析:aaa 和 abc 的相同的字符数 为1abc 和 adc 相同的字符数为2cde 和 bfcde 相同的字符数为3N个总数只有10, 很容易就想到了状态压缩,我们用dp[j][i]表示以第一个串结尾, 状态为j时 最大的相同字符数, j 的二进制位上每一个位的0 或1 表示是否已选了第几个串pku2817#include<iostream>#include&l
阅读全文
摘要:最近做了一些动态规划的题目,稍微回顾一下hdu2517 棋盘分割题意:中文题……分析:这个题目在黑书上面有,主要是将公式稍微转换一下hdu2517#include<iostream>#include<algorithm>#include<string.h>#include<stdio.h>#include<stdlib.h>#include<math.h>using namespace std;const int N = 10;const int M = 20;const int n = 8;double dp[M][N]
阅读全文
摘要:题意:给定一个n+1个点的有向图和起点,求经过其余n个点然后回到起点的最短路径。。(n<=10)分析:看到这么小的数据,就知道不是普通的最短路了,首先,n 这么小,应该联想到的应该是状态压缩吧,每一个位表示经过了哪一个点。。。dp[i][j] 表示到达点i 状态为j 时的最短路径长度,一开始忽略了一点,就是更新过的点,完全有可能再更新的,所以不能单纯记录是否更新过该状态,所以就想到了用spfa,将更新过的点入队,,继续拓展……View Code #include<iostream>#include<algorithm>#include<queue>us
阅读全文
摘要:题意:给定一个矩形,将矩形切成给定任意个数的小矩形,当然每一个小矩形都有对应的权值,求最大权值分析:其实,就是一个类似完全背包的问题dp[i][j]表示从(0,0)到(i,j)对应的矩形可以切出小矩形的最大权值和View Code #include<iostream>#include<algorithm>#include<string>using namespace std;const int N = 1000+10;struct rec{ int x,y; int p;}r[15];int dp[N][N];int main(){ int T,n,X,Y;
阅读全文
摘要:很明显的状态转移方程式:dp[i]=max(dp[j])+g[i], (0<=j<i && h[i]>h[j])不过注意到题目中n的范围有10000 ,n^2的算法…………我们可以用线段树优化一下先对高度离散化,作为线段树左右区间的端点这样,求dp[i]时,只需要查出高度(0,h[i]-1]范围内的最大值t,那么dp[i]=t+g[i], 之后,接着,更新线段树中高度为g[i],值为dp[i]的点View Code #include<iostream>#include<algorithm>#include<string>#i
阅读全文
摘要:题意:有n批人,m艘船,每艘船的容量为K, 让第i 批人上船可获利bi,但是会占据ai+1个船位,而且,整批人都在必须在同一艘船上,而且,优先级别高的那批人必须在优先级别低的人前面(包括船的所在编号,hint里面有提示)分析:参照大牛的思路,太牛逼了,dp[i]表示获得价值i需要最少的代价(占据的船位,同时保证同一批人在同一艘船上)就是一个类似01背包的过程了(同时也保证了优先级别),不过每一批人花费的代价要重新计算(根据前一个状态下剩余的船位)View Code #include<iostream>#include<algorithm>#include<stri
阅读全文
摘要:CandyTime Limit:1000MSMemory Limit:65535KBDescription:Solo和koko是两兄弟,妈妈给了他们一大袋糖,每块糖上都有自己的重量。现在他们想要将这些糖分成两堆。分糖的任务当然落到了大哥Solo的身上,然而koko要求必须两个人获得的糖的总重量“相等”(根据Koko的逻辑),要不然就会哭的。非常不幸的是,koko还非常小,并且他只会先将两个数转成二进制再进行加法,而且总会忘记进位。如当12(1100)加5(101)时: 1100+ 0101------ 1001 于是koko得到的计算结果是9(1001)。此外还有一些例子:5 + 4 = 17
阅读全文
摘要:hdu1530 Maximum Clique题意:给定一个无向图,求最大团数分析:求最大团,也就是求一个最大的完全子图,只能靠搜索了,用一个dp数组剪枝搜索思路倒是很清晰一般思路:枚举每一个点,假设选择了这个点,那么最大团组成的集合就可能是由与这个点关联的点的集合组成,接下来就是深搜选择这个集合里面的点的过程了。剪枝:1)重新排列了访问的顺序,按度数大的先访问2)用一个dp[]数组,dp[i]表示i到n-1范围内的点组成的最大团数,那么dp[i-1] 的最大可能值就是 dp[i]+1了,这个可以在搜索过程用来剪枝悲剧,怎么改都是1000+msView Code #include<iost
阅读全文
摘要:题意跟hdu1520一样,给定一棵树,要求选出若干个点,但如果选择了父节点跟儿子节点不可以同时选。。求可以选出的节点数的最大值,同时,判断该选法是否唯一;分析:前半部分很容易实现,普通的树形dp,关键是如何判断是否唯一。我们用flag[N][2]来记录每一个节点的情况flag[i][j]为真,表示唯一则可以这样判断对于叶子结点, flag[k][0] = flag[k][1] = 1.对于非叶子结点,对于i的任一儿子j,若(dp[j][0] > dp[j][1] 且 flag[j][0] == 0) 或 (dp[j][0] < dp[j][1] 且 flag[j][1] == 0)
阅读全文
摘要:题意:给定N个国家,相互之间可能存在附属关系,现在想要贿赂m个国家,已知,贿赂一个国家,那么如果该国家拥有附属国,那么他的所有附属国都可以算作已经贿赂。分析:按照国家之间的附属关系连边(有向),之后将森林转为一棵树,就变成了一棵树上的01背包了。因为国家是用名字给出的,先用字典树给名字编号……dp[i][j]表示第i个国家及其附属国中选j个国家的最小花费之前一直过不了的题,现在居然1A了,主要是思路比较清晰View Code #include<iostream>#include<algorithm>#include<string.h>#include<
阅读全文
摘要:题意:在一棵树上,找出一个节点,使得每一个节点到达该点的距离(权值*路径长度)和最短。分析:先dfs求出每一个节点到根节点的距离和,然后再一次深搜即可。交了之后悲剧的爆栈了,递归太是太深了,所以,开挂了,哈View Code #include<iostream>#include<algorithm>#include<vector>using namespace std;const int N = 100010;#pragma comment(linker, "/STACK:1024000000,1024000000") //开挂了,嘿嘿s
阅读全文
摘要:题意:给定一棵树,从1号顶点进入树中,每次可以分配人到其他可达的顶点去,杀死所有的bugs可以获取brain值,求出m个人最多能获取多少brain值。分析:树形DP,需要注意的有俩点:1)只有通过父节点才可能到达儿子节点,而且,通过父亲节点必须满足人数足够消灭该节点上的所有bugs2)对于每一棵子树而言,至少要有一个人才可能获得该子树上的brain,即使没有bugs用dp[i][j]表示派遣j个人到达以i为根的子树所能获得的最大brain值View Code #include<iostream>#include<algorithm>#include<string&
阅读全文
摘要:题意:给定一棵树,每条边都有各自的权值,要求用K个机器人(从根出发),遍历整棵数,求最小总权值分析:一开始很清楚的知道,还是一道树形背包,用dp[i][j]表示以节点i为根的子树选了j个机器人遍历的权值和。关键在j==0 时的意义的理解,一开始总处理不好,就是dp[i][0]表示的是以i为根的子树放置一个机器人遍历完子树之后又回到iView Code #include<iostream>#include<algorithm>#include<string>#include<vector>using namespace std;const int
阅读全文
摘要:题意:给定一棵树,求每一个节点所能到达的最长路径的长度分析:以编号的i的节点为例(非根节点),最长的路径长度只有俩种可能,1)子树中存在最长路径;2)通过父节点的路径中存在最长路径所以,只有分别求出每一节点对应的那俩种路径取大最大值即可,当然,根节点只存在第一种可能View Code #include<iostream>#include<algorithm>#include<string>#include<vector>using namespace std;const int N = 10010;int n,dist[N],dp[N];stru
阅读全文
摘要:题意:给定一棵树,每一节点都有一权值,要求选出总权值最大的K个点,同时这K个点中任意一个点都不能是其他节点的祖先。。分析:呵呵,一看到题目就感觉是一个树形背包了,可是节点数太多了,150000,吃不消呀,如果用二维数组保存的话,很好写呀,可是肯定爆内存的,所以开了一个临时数组保存模型跟一般的树形背包还是很像的View Code #include<algorithm>#include<vector>#include<iostream>using namespace std;const int N = 150010;vector<int> g[N];
阅读全文
摘要:大致题意是说:有n个电站,每个电站都有一定的电量,电站之间有一定距离,我们要从0点出发去占领一些电站,使得占领的电站电量之和超过总电量的一半,求达到条件所要走的最短距离。如果可能的话,输出距离,否则输出不可能。我们知道电站都是连通的,只要0点与任何一个电站连通,我们就可以占领所有电站,如果0点不与任何一个电站相连,就是不可能实现,也就是说0点到任何一个电站的距离都是无穷。 我们从0点开始派出一些坦克去占领一些电站,坦克到每个电站都有一定距离,而占领每个电站之后可以得到一定电量,距离就相当于体积,电量就相当于价值,这不是就01背包吗?01背包通常的问法是给定体积,求获得最大的价值,这里的问法是给
阅读全文
摘要:某种排序下的01背包,直接01背包肯定是错的,因为题目加了一些限制,需按q-p 从小到大将物品排序,至于为什么还是不清楚View Code #include<iostream>#include<algorithm>using namespace std;int dp[5005];struct good{ int p,q,v;}g[505];bool cmp(good a,good b){ return a.q-a.p<b.q-b.p;}int main(){ int n,m; while(scanf("%d %d",&n,&m)
阅读全文
摘要:题意:有m个工程,最多可以雇佣n个人,已知概率pij表示完成第i个工程雇佣j个人时,能按时完成的概率,同时,已知完成一个工程的奖金和无法完成时的罚款,还有每一个人的工资,当然,如果参与的工程无法按时完成,则参与的人不需要支付工资。求这m个工程的最大利润,同时求出需要的人数,多种方案时,从小到大输出人数。分析:想了想,应该还是一道DP,当这么想的时候,很快就写出了状态转移方程,不过却被一些细节拌住了,调了N久,WA了n次状态转移方程:dp[i][j]表示到第i个工程,雇佣j个人的最大利润dp[i][j]=max(dp[i-1][j-k]+pik *(reward-k*salary)-(100-p
阅读全文