随笔分类 - DP
摘要:题意: 一个三层书架,现要把一些高度和厚度不等的书放进书架,每层至少放一本,问书架面积最少是多少,且要保证书架是矩形的。 分析: 先对书按从高到低排序,不妨把最高的一本书放在第一层,这样第一层的高度就不用考虑了 dp[i][j] 表示第二层厚度为 i ,第三层厚度为 j 时第二和第三层书架高度和的最小值#include<stdio.h>#include<string.h>#include<stdlib.h>#include<algorithm>#define INF 601using namespace std;struct node{ int
阅读全文
摘要:题意:有以个 有 N 个节点的树形地图,问在这些顶点上最少建多少个电话杆,可以使得所有顶点被覆盖到,一个节点如果建立了电话杆,那么和它直接相连的顶点也会被覆盖到。分析:用最少的点覆盖所有的点,即为求最少支配集。 可以用树形DP。① dp[r][0] += min(dp[i][0],dp[i][1],dp[i][2]) dp[r][0]表示在自 r 顶点自身建, 以 r为根节点的树所需要的最少覆盖数。② dp[r][1] += min(dp[i][0],dp[i][1])dp[r][1]表示在r的子节点建, 以 r为根节点的树所需要的最少覆盖数。③ dp[r][2] += min(dp[i][0
阅读全文
摘要:题意: HAHA 早上有 n 件事情要做, 知道了有 m 个关系,每个关系 a ,b 表示a 事情必须在b 事情之前做,问做完这些事共有多少种可能的顺序。分析: 可以把题目看成是 一个有向图,其中共有多少种拓扑排序的方法。 首先图中不能有环,可以先传递闭包,看看有没有 g[i][i]=1 的情况出现,如果有则说明有环。 由于 n <=17 ,1<<17 相对较小,可以枚举所有状态进行递推。① 递归写法#include<stdio.h>#include<string.h>#define clr(x)memset(x,0,sizeof(x))int g[1
阅读全文
摘要:题意: 有个储蓄罐 ,内部物品重量已知,内部可能有 n 种钱币,知道每个钱币的重量和价值,问储蓄罐内部钱币价值最少是多少。分析: 完全背包,由于是最小价值,所以应把 数组初始为无穷大。#include<stdio.h>#include<string.h>int f[10005];int min(int a,int b){ return a<b?a:b; }int main(){ int t,i,n,v,emp,a,b; scanf("%d",&t); while(t--) { scanf("%d%d",&em
阅读全文
摘要:题意: 给定两个字符串,输出他们的最长公共子序列,要求字典序最小。分析:先用LCS算法将最长公共子序列的长度len求出来,还有数组f[i][j],表示字符串a前i个字符和字符串b前j个字符的最长公共子序列的长度,时间复杂度O(n*m)。然后将两个字符串逆序,方便求最小字典序。用两个二维数组分别记录两个字符串a和b前i个字符中字符c出现的最后位置,la[i][c],字符串a的前i个字符中,字符c出现的最后位置。la[i][c],字符串b的前i个字符中,字符c出现的最后位置。然后从最大长度len到1枚举答案的每个位置的字符,直接暴力会超时,需要优化。利用前面的f[][],la[],lb[]数组进行
阅读全文
摘要:题意:C国在成果破解J国破坏交通的阴谋之后,国王决定宴请各位大臣,合理制定宴请的人的名单的任务就交给了作为国王智囊团团长的你。你知道国王喜欢热闹,所以你希望能邀请尽量多的人,但是做为直接上下级关系的两个人直接出现在宴会上的时候会显得很尴尬,所以不能同时请有上下级关系的两个人。国王是宴会的主办方,也是这个王国的最高领袖,所以必须到场。为了能为宴会准备的更好,你需要知道整个宴会最多可以邀请多少宾客分析: f[i][1] 表示以i为根节点并包含i的子树的最大值f[i][0] 表示以i为根节点不包含i的子树的最大值 转移方程f[r][1]+=f[son][0];f[r][0]+=max(f[son][
阅读全文
摘要:题意:J国和C国爆发了战争,J国派出了很多间谍深入到C国内部,经常在C国的城市之间炸毁道路,阻拦C国的军队,C国为了抓到这些间谍,需要派人在城市进行监视,一个城市只要有一个人监视,那么这个城市的所有的道路也都会被监视到,为了能够尽量多的士兵去前线打仗,监视的士兵要尽可能的少,希望靠你编程求出至少需要多少人能实现对所有城市之间道路的监视。分析: // dp[i][0] 在 i 节点不放士兵 // dp[i][1] 在 i 节点放士兵 // dp[i][0]+=dp[j][1] // dp[i][1]+=min(dp[j][0],dp[j][1])#include<stdio.h>#i
阅读全文
摘要:题意:在比赛中会给出n个题,不同做题顺序会有不同的AC系数,假如A先做,B后做的话,B对A的AC系数为4, 反过来 B先做,A后做的话,A对B的AC系数为5,说明先做B后做A将得到更高的AC系数。设Sij表示第i题在第j题做完后才做获得的AC系数,有三道题a, b, c,做题顺序为bac,则系数和为:Sum = Sab + Scb + Sca。求一个做题顺序,使得AC系数和最大。分析: 开始当成是 环状的状态DP ,WA了几个点T T; 用dp[stat][k]表示在 状态stat 下以k题结尾的最大分数,k包含在状态stat中 f[stat][k] 表示在 状态stat 下,stat...
阅读全文
摘要:题意: 有 n 个字符串,可以改变上下顺序,可以在每个单词前加 任意的空格,计算所有单词叠在一起后每一行与上一行相应位置相同的字符数之和,找出最大和。分析: 两两字符串之间可以用 l *l 的算法计算出最大的连续相同的字符数,由于单词前可以加任意的空格数,所以单词的上下顺序不影响结果,由于字符串的长度最大为10 ,总的个数最多为10,所以可以枚举所有状态,找出最大值。#include<stdio.h>#include<string.h>#define clr(x)memset(x,0,sizeof(x))int max(int a,int b){ return a>
阅读全文
摘要:题意: 有 一个天平, 已知 m 个位置,和 n 个砝码的质量问使得天平平衡共有多少种方法。分析: 用 滚动数组 c1[8000],c2[8000], c1[i] 表示 平衡度为 i 当 0<i<8000 时 表示重心在左侧, 当 8000<i<16000 时表示重心在右侧, 最后 c1[8000] 表示的即为平衡的情况数, 递推式 c1[j]+=c2[j+a[i]*p[k]];#include<stdio.h>#include<string.h>int c1[16005],c2[16005];int p[30],a[30];int main()
阅读全文
摘要:题意: 在 n 个整数之间添加 n-1 个+ 或 - 问 运算之后能否被 k 整除。分析: 状态转移方程 dp[i][j]=dp[i-1][j-a[i]]||dp[i-1][j+a[i]]#include<stdio.h>#include<string.h>int d[10001][105];int a[10001];int main(){ int i,j,ps,ms,n,k; while(scanf("%d%d",&n,&k)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&am
阅读全文
摘要:题意:从n个人中选出m个,每个人有固定的p值,d值,要求使m个人的p总和和d总和的差的绝对值最小,若有多解则取两者和最大的。分析:dp[i][j]表示在选m个人中的第i个人的时候使所有已选中的人的b,p差为j时,所能获得的b,p最大和。 dp[i + 1][j + b[k] - p[k]] = dp[i][j] + b[k] + p[k];(要求k之前没有选过,要查看[i][j]的完整路径,确保无k) 填写完成后,观察找到最小差值,最大和。知道和差自然可以求出总的p,d。View Code #include<stdio.h>#include<string.h>#incl
阅读全文
摘要:题意: 在一个树中找出权值和最大的一个连通子集。分析: 和 1463 几乎一样的题, 状态转移方程 // dp[i][0]以i 为根节点不包含i 的值 // dp[i][1]以i为根节点包含 i的值 // dp[i][0]=max(dp[j][1],dp[j][0]) // dp[i][1]+=min(dp[j][0],dp[j][1]) j 为 i 的儿子View Code #include<stdio.h>#include<string.h>#define clr(x)memset(x,0,sizeof(x))struct node{ int x,y,w;}p[10
阅读全文
摘要:题意: 给一个固定大小的布料,给出n 个固定的尺寸,每个尺寸的布料对应一定的价值,问如何裁剪原来的布料能可以获得最大的价值。分析: 应为每个尺寸的布料都对应四种切法,(蓝色部分) 所以状态转移方程为: dp[i][j]=max(dp[i][j],max(d[i-ll][j]+d[ll][j-ww],d[i][j-ww]+d[i-ll][ww])+p); dp[i][j]=max(dp[i][j],max(d[i-ww][j]+d[ww][j-ll],d[i][j-ll]+d[i-ww][ll])+p);View Code #include<stdio.h>#include<s
阅读全文
摘要:题意: 有 n 个国家,n-1 条道路,形成的树形地图,问图中有多少对城市距离为 K ...分析: 可以用 f[i][j] 表示以 I 为根的子树中有多少定点距离 i 为 j 。因为 f[i][j]=f[son1][j-1]+f[son2][j-1]....f[son(n)][j-1] 即每个 I 号根都可以由和它直接相连的孩子得到,这个过程可以利用树形搜索的方式来完成, 至于最终答案,只要逐个累加即可,例如 f[i][j] i 号节点得到的数目为 f[i][k]+f[son1][j]*f[son2][k-2-j] (son为i 的直接孩子)View Code #include<s...
阅读全文
摘要:题意:给一个树形的图,可以在任意一个位置建造游乐场,每个游乐场都有相应的造价,如果该节点建有游乐场,那么改点的人到该游乐场就不需要花费, 否则需要花费所在位置到游乐场的路径长度对应的费用,问怎么建游乐场能使得总花费最小。分析: 树形DP。 用 f[i][j] 表示以 i 为根节点的子树以 j 为游乐场的最小花费,为了便于状态转移,这个游乐 场先不计费,f[i][j] 中的最优的 j 一定是其某个子节点,这样就长生了最优子结构,所以计算 f[i][j]时 ,f[i][j] 的值可以由其子节点来确定,状态转移方程如下: f[i][j]=d[len[i][j]]+sum...
阅读全文
摘要:题意:给你一个运动员的起始分数,分数为N,你需要计算出有多少种投掷飞镖的方式能够把分数降到0.不同的方式意味着:两两方式之间至少有一种方式的某个步骤和另一个不同,如果两个方式可以通过改变其中某种方式相应步骤的顺序来使其和另一个方式相同的话,这两种方式算作一种。分析:比较明显的母函数,只不过有个地方需要注意,就是要开两个数组来维护总的情况数,即 先求出不包含X2 的情况的组合数,然后用滚动数组c1 c2来存放至少含有一个X2的情况数,也就是 C数组里面存的都是符合条件的情况,c[j+step]+={ c[j] 里面的每种情况都符合要求 { tmp[j] 里面的每种情况都不符...
阅读全文
摘要:题意: 给你一个长度为 n 的桥,上面每个坐标分布相应数量的蚊子,告诉你一个青蛙从 0 开始向终点跳跃,最多跳 k 步,问你最多能吃多少个蚊子。分析: 状态转移方程 dp[i][j]=max(dp[i][j],dp[i-1][t]) j-r<=t<=j-l dp[i][j] 表示在 j 位置,走了 i 步的最大值。View Code #include<stdio.h>#include<string.h>#define max(a,b)(a)>(b)?(a):(b)int dp[200][103];int a[10002];int main(){ int
阅读全文
摘要:题意: 有 n 个物品,有主件附件之分,买附件必须先买主件,问最后可以得到的价值最大是多少?分析: 分组背包的变形。View Code #include<stdio.h>#include<string.h>#define max(a,b)(a)>(b)?(a):(b)int w[100];struct node{ int to,next;}q[100];int head[61];int num[61];int tot;void add(int s,int u){ q[tot].to=u; q[tot].next=head[s]; head[s]=tot++;}in
阅读全文
摘要:题意: 给你两条街,上面的街编号从 1-n 下面的也是,然后告诉你他们的一些边, 让你从中尽可能选出多的边,使他们两两之间没有交点。分析: LIS 的变形,把一条街看成有序的,求令一条街的最长递增子序列, 因为当 上面 i < j 时 有 f[i]<f[j]。View Code #include<stdio.h>#include<string.h>int d[500005];int l[500005];int bis(int len,int x){ int low=0,high=len-1,mid; while(low<=high) { mid=(l.
阅读全文