DP类型各题总结-acm

合集下载

acm试题及答案2

acm试题及答案2

acm试题及答案2ACM试题及答案21. 问题描述:编写一个程序,计算给定整数序列中的最大子段和。

2. 输入格式:第一行包含一个整数N,表示序列的长度。

第二行包含N个整数,表示序列中的整数。

3. 输出格式:输出一个整数,表示序列中的最大子段和。

4. 样例输入:```51 -2 -34 -1```5. 样例输出:```6```6. 问题分析:该问题可以通过动态规划的方法来解决。

定义一个数组dp,其中dp[i]表示以第i个元素结尾的最大子段和。

状态转移方程为dp[i] = max(dp[i-1] + nums[i], nums[i])。

7. 算法实现:```pythondef maxSubArray(nums):n = len(nums)dp = [0] * ndp[0] = nums[0]max_sum = nums[0]for i in range(1, n):dp[i] = max(dp[i-1] + nums[i], nums[i])max_sum = max(max_sum, dp[i])return max_sum```8. 复杂度分析:时间复杂度为O(n),其中n为序列的长度。

空间复杂度为O(n)。

9. 测试用例:- 输入:`[3, -2, 4]`输出:`5`- 输入:`[-2, 1, -3, 4, -1, 2, 1, -5, 4]`输出:`6`10. 注意事项:- 确保输入的序列长度N大于等于1。

- 序列中的整数可以是负数或正数。

- 输出结果应该是一个整数。

11. 扩展思考:- 如何优化算法以减少空间复杂度?- 如果序列中的整数是浮点数,算法是否仍然有效?12. 参考答案:- 可以通过只使用一个变量来存储最大子段和,以及一个变量来存储当前子段和,从而将空间复杂度优化到O(1)。

- 如果序列中的整数是浮点数,算法仍然有效,但需要注意浮点数运算的精度问题。

图论类型各题总结-acm

图论类型各题总结-acm

hdu4318 Power transmission 最短路当数据很大的时候的解决办法一道题目的解题全过程记录最短路解决大数据模拟链表Power transmissionTime Limit: 10000/5000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 663 Accepted Submission(s): 231Problem DescriptionThe project West-East power transmission is famous around the world. It transmits the electricity from western areas to east China. There are many nodes in the power system. Each node is connected with several other nodes in the system by cable. Power can be only transmitted between two connected nodes. For each node, it can’t send power to two or more other nodes at the same time.As we have all known, power will be loss during the transmission. Bob is the chief engineer of the project. He wants to build a transmission line which send power from one node to another node and minimize the power loss at the same time. Now he asks you to help him solve the problem.InputThere are several test cases. For each test case, the first line contains an integer N (0 < N ≤ 50000) which represents the number of nodes in the power system. Then there will be N groups of data following. For the i-th(0 < i ≤ N) group, the first line is an integer ki (ki ≤ 50), which means the node i is connected with ki nodes. The rest of the i-th group data are divided into ki lines. Each line contains an integer ai (0 < ai ≤ N, ai ≠ i) and an integer bi (0 ≤ bi ≤ 100), which represents power can be transmitted from node i to ai and will loss bi% while transmitting. The last line of input data contains three integers separated by single spaces. The first one is s, the second is t (0 < s, t ≤ N), and the third is the total power M (0 < M ≤ 10^6) at node s.OutputFor each test case, output the minimum of loss power while transmitting from node s to node t. The result should be printed with two digits to the right of the decimal point. If power cannot be transmitted from node s to node t, output “IMPOSSIBLE!” in a line.Sample Input422 503 7021 304 2021 104 401 4 100Sample Output60.00HintIn the sample, the best transmission line is 1 -> 2 -> 4, loss power is 100 * 50% + 100 * (100%-50%)*20% = 60.00MicrosoftInternetExplorer402DocumentNotSpecified7.8Normal0题意:多个点从一个点往另一个点运输天然气但是从某点到另外一点是会有损耗的题中输入的即为损耗的百分数问从点s到t最少损耗多少分析: 很明显是最短路问题但是有个比较卡人的地方就是最多会有50000个点数据太大用map数组存不下会爆掉我们考虑到用链表就用了数组去模拟链表保存从当前点能到达的点队长把写解题报告的任务光荣的交给了我但是我对看代码表示相当的纠结所以就自己去写了个好理解把自己的贴上/*#include<stdio.h>#include<string.h>struct haha{int son[55]; //记录从当前点到其它能走到的点double son_val[55]; //记录从当前点到其它能走到的点的消耗int cnt;//记录存取的儿子个数}a[50100];int n,flag,s,t,M,used[50100];double min[50100];double find_short()//模拟以前数据比较小的时候的模板{int i,j,pos,cnt;double mm;memset(used,0,sizeof(used));for(i=1;i<=n;i++) min[i]=1;cnt=a[s].cnt;while(cnt--){min[a[s].son[cnt]]=a[s].son_val[cnt];}used[s]=1;min[s]=0;for(i=2;i<=n;i++){mm=1;for(j=1;j<=n;j++){if(!used[j]&&mm>min[j]){pos=j;mm=min[j];}}if(mm==1) {flag=1;return 0;}used[pos]=1;cnt=a[pos].cnt;for(j=0;j<cnt;j++){if(!used[a[pos].son[j]]&&min[pos]+(1.0-min[pos])*a[pos].son_val[j]<min[a[pos].son[j]])min[a[pos].son[j]]=min[pos]+(1.0-min[pos])*a[pos].son_val[j];}if(pos==t) return min[t];//这里很重要不加会超时的哦}return min[t];}int main(){int i,m,x,y;double val,k;while(scanf("%d",&n)!=EOF){flag=0;for(i=1;i<=n;i++)a[i].cnt=0;for(i=1;i<=n;i++){scanf("%d",&m);while(m--){scanf("%d %d",&x,&y);val=y/100.0;a[i].son[a[i].cnt]=x;a[i].son_val[a[i].cnt++]=val;}}scanf("%d %d %d",&s,&t,&M);k=find_short();if(flag==1) {printf("IMPOSSIBLE!\n");continue;}printf("%.2lf\n",k*M);}return 0;}*/hdu1596 find the safest road 最短路也能求最大值分类:图论2012-07-27 23:21177人阅读评论(0)收藏编辑删除find the safest roadTime Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2477 Accepted Submission(s): 978Problem DescriptionXX 星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每一条路有一个安全系数s,s是在0 和 1 间的实数(包括0,1),一条从u 到v 的通道P 的安全度为Safe(P) = s(e1)*s(e2)…*s(ek) e1,e2,ek是P 上的边,现在8600 想出去旅游,面对这这么多的路,他想找一条最安全的路。

DP基础题型总结

DP基础题型总结

DP基础题型总结DP是⼀个不能更常⽤的算法了,这⾥也就对基础的五⼤类DP题型做个总结。

⽬录背包型背包问题是很多教材上DP的引⼊题,它也确实是基础中的基础,总的来说背包型DP有01背包、部分背包、完全背包三种,其余的例如多重背包等都是衍⽣题⽬。

直接看例题吧。

先看⼀道01背包。

这类题⽬只有两种状态,拿或不拿,所以叫01背包。

状态转移⽅程还是⽐较好写的:f[i] = max{f[i], f[i-x]+x}。

f[i]表⽰选到i的最⼤容积(箱内容积),最后⽤总的去减去f[v]就是ans。

#include<iostream>using namespace std;int v, n, a;int f[100005];int main(){cin >> v >> n;for (int i = 1; i <= n; i++){cin >> a;for (int j = v ; j >= a; j--){if (f[j] < f[j-a] + a)f[j] = f[j-a] + a;}}cout << v - f[v];} 01背包就是这么简单。

接下来看⼀道唬⼈⼀点的01背包。

这如果没有"数据保证到达终点时⼀定⽤完M张爬⾏卡⽚"这句话的话这道题会⿇烦不少,但是有这句话的话就可以把它看做⼀个多维的01背包,⽤dp[a][b][c][d];来分别表⽰选四种卡的情况就可以了。

#include <cstdio>#include <iostream>using namespace std;int n, m;int map[500];int dp[45][45][45][45];template<class T>inline void read(T &res){static char ch;while( (ch=getchar()) < '0' || ch > '9');res = ch - 48;while( (ch = getchar() ) >= '0' && ch <= '9')res = ch - 48 + res * 10;}int main(){int a = 0;int b = 0;int c = 0;int d = 0;read(n);read(m);for (int i = 0; i < n; i++)read(map[i]);for (int k, i = 1; i <= m; i++)看的出来其实也就是选或者不选的状态,只是维度⽐较多⽽已,还是⽐较裸的。

dp总结

dp总结

BZOJ1004
Description
何劲范现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前何劲范只有3种颜色:红色,蓝色,绿色.他询 问Sun有 多少种染色方案,Sun很快就给出了答案.进一步,何劲范要求染出Sr张红色,Sb张蓝色,Sg张绝色.他又询问有多少 种方 案,Sun想了一下,又给出了正确答案. 最后何劲范发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色 方案. 两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次) 洗 成另一种.Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).
Input
第一行一个N,表示序列一共有N个元素第二行N个数,为a1,a2,…,an 第三行一个M,表示询问次数。下 面接M 行每行一个数L,表示要询问长度为L的上升序列。N<=10000,M<=1000
Output
对于每个询问,如果对应的序列存在,则输出,否则打印Impossible.
首先求出以每个数为开头上升序列长度,即倒着做最长下降子序列 然后,把字典序尽量小的放前面 即若要求的序列长度为x,如果以第一个数(字典序最小的数)开头的最长上升子 序列大等于x,则将它放在答案第一个,第二个数开头小于x,则舍弃,第三个大于 x-1,放答案第二个,以此类推
• • • • • • •
我们令dp[i][j]表示i-j这段区间最少涂色次数 分两种情况 1:s[i] s[j]一样 f[i][j]=min(f[i+1][j],f[i][j-1]); f[i][j]=min(f[i][j],f[i+1][j-1]+1); 2:s[i] s[j]不一样 f[i][j]=min(f[i][k]+f[k+1][j],f[i][j])

牛人的ACM-POJ的题型分类总结!

牛人的ACM-POJ的题型分类总结!

⽜⼈的ACM-POJ的题型分类总结!主流算法:1.搜索//回溯2.DP(动态规划)3.贪⼼4.图论//Dijkstra、最⼩⽣成树、⽹络流5.数论//解模线性⽅程6.计算⼏何//凸壳、同等安置矩形的并的⾯积与周长7.组合数学//Polya定理8.模拟9.数据结构//并查集、堆10.博弈论1、排序1423,1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380,1318, 1877, 1928, 1971, 1974, 1990, 2001, 2002, 2092, 2379,1002(需要字符处理,排序⽤快排即可) 1007(稳定的排序) 2159(题意较难懂) 2231 2371(简单排序) 2388(顺序统计算法) 2418(⼆叉排序树)2、搜索、回溯、遍历1022 1111 1118 1129 1190 1562 1564 1573 1655 2184 2225 2243 2312 2362 2378 23861010,1011,1018,1020,1054,1062,1256,1321,1363,1501,1650,1659,1664,1753,2078,2083,2303,2310,2329简单:1128,1166, 1176, 1231, 1256, 1270, 1321, 1543, 1606, 1664, 1731, 1742, 1745,1847, 1915, 1950, 2038, 2157, 2182, 2183, 2381, 2386, 2426,不易:1024, 1054, 1117, 1167, 1708, 1746, 1775, 1878, 1903, 1966, 2046, 2197, 2349, 推荐:1011,1190, 1191, 1416, 1579, 1632, 1639, 1659, 1680, 1683, 1691, 1709,1714,1753, 1771, 1826, 1855, 1856, 1890, 1924, 1935, 1948, 1979, 1980, 2170,2288, 2331, 2339, 2340,1979(和迷宫类似)1980(对剪枝要求较⾼)3、历法1008 2080 (这种题要⼩⼼)4、枚举1012,1046, 1387, 1411, 2245, 2326, 2363, 2381,1054(剪枝要求较⾼),1650 (⼩数的精度问题)5、数据结构的典型算法容易:1182, 1656, 2021, 2023, 2051, 2153, 2227, 2236, 2247, 2352, 2395, 不易:1145, 1177, 1195, 1227, 1661, 1834,推荐:1330, 1338, 1451, 1470, 1634, 1689, 1693, 1703, 1724, 1988, 2004, 2010, 2119, 2274, 1125(弗洛伊德算法),2421(图的最⼩⽣成树)6、动态规划1037 A decorative fence、1050 To the Max、1088 滑雪、1125 Stockbroker Grapevine、1141 Brackets Sequence、1159 Palindrome、1160 Post Office、1163 The Triangle、1458 Common Subsequence、1579 Function Run Fun、1887 Testing the CATCHER、1953 World Cup Noise、2386 Lake Counting7、贪⼼1042, 1065, 1230, 1323, 1477, 1716, 1784,1328 1755(或⽤单纯形⽅法),2054,1017, 1328,1862,1922 ,2054,2209, 2313, 2325, 2370。

ACM题目分类

ACM题目分类
三.数据结构.
(1)串 (poj1035,poj3080,poj1936)
(2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
(3)简单并查集的应用.
(4)哈希表和二分查找等高效查找法(数的Hash,串的Hash)
(3)点集最小圆覆盖.
(4)对踵点(poj2079)
八.综合题.
(poj3109,poj1478,poj1462,poj2729,poj2048,poj3336,poj3315,poj2148,poj1263)
同时由于个人练习的时候可能有些偏向性,可能上面的总结不是很全,还请大家提出和指正,而且由于ACM的题目中专门针对某个算法的题目可能比较少出现,所以上面的分类中的题有可能有多种解法或者是一些算法的综合,这都不会影响大家做题,希望练习的同学能够认真,扎实地训练,做到真正的理解算法,掌握算法. 同时在论坛上还有许多前辈的分类,总结,大家也可以按自己的情况采用.注意FTP上有很多的资料,希望大家好好地利用.
目的). (poj2823)
(4)左偏树(可合并堆).
(5)后缀树(非常有用的数据结构,也是赛区考题的热点).
(poj3415,poj3294)
四.搜索
(1)较麻烦的搜索题目训练(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)
(5)杂题.
(poj1870,poj3296,poj3286,poj1095)
七.计算几何学.
(1)坐标离散化.
(2)扫描线算法(例如求矩形的面积和周长并,常和线段树或堆一起使用).
(poj1765,poj1177,poj1151,poj3277,poj2280,poj3004)

acm中dp问题简单入门讲解

acm中dp问题简单入门讲解

ACM暑期集训报告院系:专业:年级:学号:姓名:日期:西南交通大学目录目录.................................................. 错误!未定义书签。

第1章动态计划(dp) ............................ 错误!未定义书签。

简介.................................................... 错误!未定义书签。

教师内容................................................ 错误!未定义书签。

大体dp——背包问题..................................... 错误!未定义书签。

假设干经典dp及常见优化.................................. 错误!未定义书签。

类似题目................................................. 错误!未定义书签。

参考文献........................................... 错误!未定义书签。

附录1 暑期集训心得体会............................. 错误!未定义书签。

第1章动态计划(dp)(题目采纳2号黑体居中,下空1行)简介(题目采纳四号黑体,正文内容采纳小四号字体,倍行距)在解决问题的时候咱们常常碰到这种问题:在多种方式的操作下咱们如何取得一个最优的方式让咱们取得中意的结果。

这时咱们大多人的思想确实是贪婪。

不错贪婪确实是一个不错的算法,第一他简单容易想到,咱们在操作起来也比较容易。

此刻我推荐几道咱们oj上的贪婪算法的题:soj1562药品运输 soj1585 Climbing mountain。

为了引入动归算法我先拿药品运输这道题简单说一下贪婪算法。

例如1:药品运输(题目采纳小四号Times New Roman字体)Description大地震后,某灾区急需一批药品,此刻有N种药品需要运往灾区,而咱们的运输能力有限,此刻仅有M辆运输车用来运输这批药品,已知不同的药品对灾区具有不同的作用(“作用”用一个整数表示其大小),不同的药品需要的运输力(必要的车辆运载力)不同,而不同的车辆也具有不同的运输力。

ACM培训-基础dp

ACM培训-基础dp

例2
怎么办? 不怕。最暴力的解决方式就是,我们把影响的原因放到 状态里。 现在影响第i个物品能不能拿的原因,是现在背包剩余多 大。也就是说,背包空间制约了第i个物品能不能拿。
例2
我们重新定义状态。 设dp[i][v]表示现在有一个容量为v的背包,选择到第i个物 品,所能得到的最大的价值。 那我们再来写状态转移方程看看。 对于第i个物品,无非拿或者不拿。如果拿了,那么背包 剩余的空间会变小。假设第i个物品的体积为c[i],价值为 val[i],那么我们不难得到下面这条状态转移方程: dp[i][v] = max(dp[i-1][v], dp[i-1][ v-c[i] ] + val[i]) 前者是不拿第i个物品的情况 后者是拿第i个物品情况。 很好,我们解决状态转移方程了。
引入
于是,小乐乐躺在床上想, 我走到大门的方式,无非两 种。一种是从大门左边那个 房间走到大门,一种就是个房 间所花费的最小力气,那走 到大门的最小力气不就很容 易算了?
引入
小乐乐继续想。假设我现在知道走到蓝色格子所花费的 最小力气是dp[蓝],走到红色格子所花费的最小力气是 dp[红],那么,走到大门所需要的最小力气就是 Min(dp[蓝]+8, dp[红]+1)
例2
来……我们思考一下。 关键就是在与状态的定义。
例2
好的,那我们来一起暴力dp. 首先是状态的定义。
我们需要求最大的价值。那我们就把状态定义成最大的 价值好了。可是定义在哪呢?
那我们就把化妆品排成一排放好了。dp[i]就表示小乐乐 从前往后选,选到第i个化妆品时,所能得到的最大价值。 那我们尝试写状态转移方程。每个物品,无非拿或者不 拿。不拿好说,如果拿的话,我们碰到一个困难:现在 背包空间够不够呢?能不能拿呢? 这时我们发现,第i个物品所做的决策,受到前面是如何 拿的影响,看起来,我们的状态设置的有点问题。

ACM+DP+算法++大集合

ACM+DP+算法++大集合

第27 讲贪心与动态规划虽然都是求解最优化问题,第一部分贪心(Greedy)在求解最优化问题时,有这样一种自然的想法,希望每一步都则采取最优的策略,最终得到全局的最优解,这就是贪心思想。

它的最大特点就是运行速度快,效率高,因此备受程序设计员的喜爱。

当然,由此也带来了贪心法的最大问题,如何证明其正确性?因为在很多时候,局部最优解的选择往往最终得不到全局最优解。

于是,我们在运用贪心思想解决问题时,就需要格外的小心。

事实上,许多成熟的算法中都蕴含了贪心思想,比如求解最小生成树的Bellman-Ford算法,单源最短路径的Dijkstra算法,求解二分图匹配的匈牙利算法等等。

很多时候,贪心法虽然得不到最优解,但是仍具有重要的最用。

比如,利用贪心法得到的近似解可以为搜索法提供较强的剪枝策略。

就用一个例子来看看贪心法的应用吧:[例 1, POJ 2287] 田忌赛马田忌赛马的故事想必已经被大家所熟知了,孙膑“以君之下驷彼上驷,取君上驷与彼中驷,取君中驷与彼下驷”的策略使得田忌最终“一不胜而再胜”。

如今,田忌与齐王决定再战一场,这一回双方决定用 n (n ≤ 1000)匹马较量一番。

每一回合,先到的马将为主人赢得200美元,如果打平双方均无需指出。

假设双方马匹的速度已给出,而田忌仍然能够提前知道齐王马匹的出场顺序,那么他最多能赢多少钱呢?[分析]乍看下去,似乎没有很好的贪心思路,倒是可以利用二分图匹配的方法解题,可是时间复杂度相对较高,改进得的匈牙利算法也匹配需要O (n 3)的时间,即使Hopcraft 算法,也需要O (2n n )的时间复杂度。

那么,真的不能运用贪心法吗?当年田忌获胜的方法或许能够给我们一些启迪。

用下等马匹配齐王的上等马,虽然输掉了局部,却赢下了全局。

也就是说,在最终的最优选择中,将有一些场次会输掉比赛。

那么,既然是这样,我们何不学习田忌,用那些“下等马”输掉这些比赛,而让获胜者,均为齐王的“上等马”呢?这样的改进不会比原先的最优选择更差。

DP动态规划ACM课件

DP动态规划ACM课件
}
return sum;
}
引申问题: 最大子矩阵和问题 最大m段子段和问题
▪ 最长递增子序列(LIS)
▪ 常规DP,时间复杂度为O(n2)。
▪ 存在一种特殊的方法,时间复杂度为 O(n*logk)。
▪ 推荐题目: POJ1631 Bridging Signals
POJ1631参考代码
▪ #include<iostream>

for(i=1;i<=n;i++)

scanf("%d%d",&v[i][0],&v[i][1]);

l=l*1000;

if(l >= 450000) {printf("0\n");continue;}

memset(f,0,sizeof(int)*(l+1));

memset(fff,0,sizeof(fff));
E 阶段4
▪ 设 Dis[k][x] 为第k阶段城市x到城市E的最短路径长度。 map[ i ][ j ]为i,j两个城市间的距离。
▪ 递归方程为 Dis[k][x] = min { Dis[k+1][y]+map[x,y] }
▪ 此问题时间复杂度降为O(n2).
▪ 状态:贴切,简洁的描述出事物性质的单元量。例如: Dis[x]。 要求:状态与状态之间可以转移,以便有初始状态逐渐转移 到目标状态,找到问题的解。
▪ 阶段:若干性质相近可以同时处理的状态的集合。就是计算 状态的顺序。 要求:每个阶段中状态的取值只与这个阶段之前的阶段中的 状态有关,与这个阶段之后的阶段中的状态无关。
▪ 状态转移方程:前一个阶段中的状态转移到后一个 阶段的状态得演变规律,即相邻两个阶段的状态变 化方程。

DP算法总结

DP算法总结

1. 资源问题1-----机器分配问题f[i,j]:=max(f[i-1,k]+w[i,j-k]);2. 资源问题2------01背包问题f[i,j]:=max(f[i-1,j-v[i]]+w[i],f[i-1,j]);3. 线性动态规划1-----朴素最长非降子序列f[i]:=max{f[j]+1}4. 剖分问题1-----石子合并f[i,j]:=min(f[i,k]+f[k+1,j]+sum[i,j]);5. 剖分问题2-----多边形剖分f[i,j]:=min(f[i,k]+f[k,j]+a[k]*a[j]*a[i]);6. 剖分问题3------乘积最大f[i,j]:=max(f[k,j-1]*mult[k,i]);7. 资源问题3-----系统可靠性(完全背包)f[i,j]:=max{f[i-1,j-c[i]*k]*P[I,x]};8. 贪心的动态规划1-----快餐问题f[i,j,k]:=max{f[i-1,j',k']+(T[i]-(j-j')*p1-(k-k')*p2) div p3};9. 贪心的动态规划2-----过河f[i]=min{{f(i-k)} (not stone[i]){f(i-k)}+1} (stone[i]); +贪心压缩状态10. 剖分问题4-----多边形-讨论的动态规划F[i,j]:=max{正正f[I,k]*f[k+1,j];负负g[I,k]*f[k+1,j];正负g[I,k]*f[k+1,j];负正f[I,k]*g[k+1,j];} g为min11. 树型动态规划1-----加分二叉树(从两侧到根结点模型)F[i,j]:=max{f[i,k-1]*f[k+1,j]+c[k]};12. 树型动态规划2-----选课(多叉树转二叉树,自顶向下模型)f[i,j]表示以i为根节点选j门功课得到的最大学分f[i,j]:=max{f[t[i].l,k]+f[t[i].r,j-k-1]+c[i]};13. 计数问题1-----砝码称重f[f[0]+1]=f[j]+k*w[j];(1<=i<=n; 1<=j<=f[0]; 1<=k<=a[i];)14. 递推天地1------核电站问题f[-1]:=1; f[0]:=1;f[i]:=2*f[i-1]-f[i-1-m];15. 递推天地2------数的划分f[i,j]:=f[i-j,j]+f[i-1,j-1];16. 最大子矩阵1-----一最大01子矩阵f[i,j]:=min(f[i-1,j],v[i,j-1],v[i-1,j-1])+1;ans:=maxvalue(f);17. 判定性问题1-----能否被4整除g[1,0]:=true; g[1,1]:=false; g[1,2]:=false; g[1,3]:=false; g[i,j]:=g[i-1,k] and ((k+a[i,p]) mod 4 = j)18. 判定性问题2-----能否被k整除f[i,j±n[i] mod k]:=f[i-1,j]; -k<=j<=k; 1<=i<=n20. 线型动态规划2-----方块消除游戏f[i,i-1,0]:=0f[i,j,k]:=max{f[i,j-1,0]+sqr(len(j)+k), //dof[i,p,k+len[j]]+f[p+1,j-1,0] //not do}; ans:=f[1,m,0];21. 线型动态规划3-----最长公共子串,LCS问题f[i,j]=0 (i=0)&(j=0);f[i-1,j-1]+1 (i>0,j>0,x[i]=y[j]);max{f[i,j-1]+f[i-1,j]}} (i>0,j>0,x[i]<>y[j]);22. 最大子矩阵2-----最大带权01子矩阵O(n^2*m)枚举行的起始,压缩进数列,求最大字段和,遇0则清零23. 资源问题4-----装箱问题(判定性01背包)f[j]:=(f[j] or f[j-v[i]]);24. 数字三角形1-----朴素の数字三角形f[i,j]:=max(f[i+1,j]+a[I,j],f[i+1,j+1]+a[i,j]);25. 数字三角形2-----晴天小猪历险记之Hill同一阶段上暴力动态规划f[i,j]:=min(f[i,j-1],f[i,j+1],f[i-1,j],f[i-1,j-1])+a[i,j];26. 双向动态规划1数字三角形3-----小胖办证f[i,j]:=max(f[i-1,j]+a[i,j],f[i,j-1]+a[i,j],f[i,j+1]+a[i,j]);27. 数字三角形4-----过河卒//边界初始化f[i,j]:=f[i-1,j]+f[i,j-1];28. 数字三角形5-----朴素的打砖块f[i,j,k]:=max(f[i-1,j-k,p]+sum[i,k],f[i,j,k]);29. 数字三角形6-----优化的打砖块f[i,j,k]:=max{g[i-1,j-k,k-1]+sum[i,k]};30. 线性动态规划3-----打鼹鼠’f[i]:=f[j]+1;(abs(x[i]-x[j])+abs(y[i]-y[j])<=t[i]-t[j]);31. 树形动态规划3-----贪吃的九头龙f[i,j,k]:=min(f[x1,j1,1]+f[x2,j-j1-1,k]+d[k,1]*cost[i,fa[i]]] {Small Head}, f[x1,j1,0]+f[x2,j-j1,k]+d[k,0]*cost[i,fa[i]] {Big Head});f[0,0,k]:=0; f[0,j,k]:=max(j>0)d[i,j]:=1 if (i=1) and (j=1)1 if (i=0) and (j=0) and (M=2)0 else32. 状态压缩动态规划1-----炮兵阵地Max(f[Q*(r+1)+k],g[j]+num[k]);If (map[i] and plan[k]=0) and((plan[P] or plan[q]) and plan[k]=0);33. 递推天地3-----情书抄写员f[i]:=f[i-1]+k*f[i-2];34. 递推天地4-----错位排列f[i]:=(i-1)(f[i-2]+f[i-1]);f[n]:=n*f[n-1]+(-1)^(n-2);35. 递推天地5-----直线分平面最大区域数f[n]:=f[n-1]+n:=n*(n+1) div 2 + 1;36. 递推天地6-----折线分平面最大区域数f[n]:=(n-1)(2*n-1)+2*n;37. 递推天地7-----封闭曲线分平面最大区域数f[n]:=f[n-1]+2*(n-1);:=sqr(n)-n+2;38 递推天地8-----凸多边形分三角形方法数f[n]:=C(2*n-2,n-1) div n;对于k边形f[k]:=C(2*k-4,k-2) div (k-1); //(k>=3)39 递推天地9-----Catalan数列一般形式1,1,2,5,14,42,132f[n]:=C(2k,k) div (k+1);40 递推天地10-----彩灯布置排列组合中的环形染色问题f[n]:=f[n-1]*(m-2)+f[n-2]*(m-1); (f[1]:=m; f[2]:=m(m-1);41 线性动态规划4-----找数线性扫描sum:=f[i]+g[j];(if sum=Aim then getout; if sum<Aim then inc(i) else inc(j);)42 线性动态规划5-----隐形的翅膀min:=min{abs(w[i]/w[j]-gold)};if w[i]/w[j]<gold then inc(i) else inc(j);43 剖分问题5-----最大奖励f[i]:=max(f[i],f[j]+(sum[j]-sum[i])*i-t;44 最短路1-----Floydf[i,j]:=max(f[i,j],f[i,k]+f[k,j]);ans[q[i,j,k]]:=ans[q[i,j,k]]+s[i,q[i,j,k]]*s[q[i,j,k],j]/s[i,j];45 剖分问题6-----小H的小屋F[l,m,n]:=f[l-x,m-1,n-k]+S(x,k);46 计数问题2-----陨石的秘密(排列组合中的计数问题)Ans[l1,l2,l3,D]:=f[l1+1,l2,l3,D+1]-f[l1+1,l2,l3,D];F[l1,l2,l3,D]:=Sigma(f[o,p,q,d-1]*f[l1-o,l2-p,l3-q,d]);47 线性动态规划------合唱队形两次F[i]:=max{f[j]+1}+枚举中央结点48 资源问题------明明的预算方案:加花的动态规划f[i,j]:=max(f[i,j],f[l,j-v[i]-v[fb[i]]-v[fa[i]]]+v[i]*p[i]+v[fb[i]]*p[fb[i]]+v[fa[i]]*p[fa[i]]);49 资源问题-----化工场装箱员50 树形动态规划-----聚会的快乐f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,3]);51 树形动态规划-----皇宫看守f[i,2]:=max(f[i,0],f[i,1]);f[i,1]:=sigma(f[t[i]^.son,0]);f[i,0]:=sigma(f[t[i]^.son,2]);52 递推天地-----盒子与球f[i,1]:=1;f[i,j]:=j*(f[i-1,j-1]+f[i-1,j]);53 双重动态规划-----有限的基因序列f[i]:=min{f[j]+1}g[c,i,j]:=(g[a,i,j] and g[b,i,j]) or (g[c,i,j]);54 最大子矩阵问题-----居住空间f[i,j,k]:=min(min(min(f[i-1,j,k],f[i,j-1,k]),min(f[i,j,k-1],f[i-1,j-1,k])),min(min(f[i-1,j,k-1],f[i,j-1,k-1] ),f[i-1,j-1,k-1]))+1;55 线性动态规划------日程安排f[i]:=max{f[j]}+P[I]; (e[j]<s[i])56 递推天地------组合数C[i,j]:=C[i-1,j]+C[i-1,j-1];C[i,0]:=157 树形动态规划-----有向树k中值问题F[I,r,k]:=max{max{f[l[i],I,j]+f[r[i],I,k-j-1]},f[f[l[i],r,j]+f[r[i],r,k-j]+w[I,r]]};58 树形动态规划-----CTSC 2001选课F[I,j]:=w[i](if i∈P)+f[l[i],k]+f[r[i],m-k](0≤k≤m)(if l[i]<>0);59 线性动态规划-----多重历史f[i,j]:=sigma{f[i-k,j-1]}(if checked);60 背包问题(+-1背包问题+回溯)-----CEOI1998 Substractf[i,j]:=f[i-1,j-a[i]] or f[i-1,j+a[i]];61 线性动态规划(字符串)-----NOI 2000 古城之谜f[i,1,1]:=min{f[i+length(s),2,1], f[i+length(s),1,1]+1};f[i,1,2]:=min{f[i+length(s),1,2]+words[s],f[i+length(s),1,2]+words[s]};62 线性动态规划-----最少单词个数f[i,j]:=max{f[i,j],f[u-1,j-1]+l};63 线型动态规划-----APIO2007 数据备份状态压缩+剪掉每个阶段j前j*2个状态和j*2+200后的状态贪心动态规划f[i]:=min(g[i-2]+s[i],f[i-1]);64 树形动态规划-----APIO2007 风铃f[i]:=f[l]+f[r]+{1 (if c[l]<c[r])};g[i]:=1(d[l]<>d[r]) 0(d[l]=d[r]);g[l]=g[r]=1 then Halt;65 地图动态规划-----NOI 2005 adv19910F[t,i,j]:=max{f[t-1,i-dx[d[[t]],j-dy[d[k]]]+1],f[t-1,i,j];66 地图动态规划-----优化的NOI 2005 adv19910F[k,i,j]:=max{f[k-1,i,p]+1} j-b[k]<=p<=j;67 目标动态规划-----CEOI98 subtraF[I,j]:=f[I-1,j+a[i]] or f[i-1,j-a[i]];68 目标动态规划----- Vijos 1037搭建双塔问题F[value,delta]:=g[value+a[i],delta+a[i]] or g[value,delta-a[i]];69 树形动态规划-----有线电视网f[i,p]:=max(f[i,p],f[i,p-q]+f[j,q]-map[i,j]);leaves[i]>=p>=l, 1<=q<=p;70 地图动态规划-----vijos某题F[i,j]:=min(f[i-1,j-1],f[i,j-1],f[i-1,j]);71 最大子矩阵问题-----最大字段和问题f[i]:=max(f[i-1]+b[i],b[i]); f[1]:=b[1];72 最大子矩阵问题-----最大子立方体问题枚举一组边i的起始,压缩进矩阵B[I,j]+=a[x,I,j];枚举另外一组边的其实,做最大子矩阵73 括号序列-----线型动态规划f[i,j]:=min(f[i,j],f[i+1,j-1] (s[i]s[j]=”()”or(”[]”)),f[i+1,j+1]+1 (s[j]=”(”or”[” ) , f[i,j-1]+1(s[j]=”)”or”]”);74 棋盘切割-----线型动态规划f[k,x1,y1,x2,y2]=min{min{f[k-1,x1,y1,a,y2]+s[a+1,y1,x2,y2],f[k-1,a+1,y1,x2,y2]+s[x1,y1,a,y2]};75 概率动态规划-----聪聪和可可(NOI2005)x:=p[p[i,j],j];f[I,j]:=(f[x,b[j,k]]+f[x,j])/(l[j]+1)+1;f[I,i]=0;f[x,j]=1;76 概率动态规划-----血缘关系F[A, B]=(f[A0, B]+P[A1, B])/2;f[i,i]=1;f[i,j]=0;(i,j无相同基因)77 线性动态规划-----决斗F[i,j]=(f[i,j] and f[k,j]) and (e[i,k] or e[j,k]); (i<k<j)78 线性动态规划-----舞蹈家F[x,y,k]=min(f[a[k],y,k+1]+w[x,a[k]],f[x,a[k],k+1]+w[y,a[k]]);79 线性动态规划-----积木游戏F[i,a,b,k]=max(f[a+1,b,k],f[i+1,a+1,a+1,k],f[i,a+1,a+1,k]);80 树形动态规划(双次记录)-----NOI2003 逃学的小孩朴素的话枚举节点i和离其最远的两个节点j,k O(n^2)每个节点记录最大的两个值,并记录这最大值分别是从哪个相邻节点传过来的。

南京大学厦门大学ACM百练算法设计与分析OpenJudge第六章习题解答

南京大学厦门大学ACM百练算法设计与分析OpenJudge第六章习题解答

第6章课后作业结题报告第一题:给定n种物品和一个背包,物品i(1≤i≤n)的重量是wi,其价值为vi,背包的容量为C,对每种物品只有两种选择:装入背包或者不装入背包。

如何选择装入背包的物品,使得装入背包中物品的总价值最大?这是一道老生常谈的背包问题,属于入门dp(Dynamic Programming动态规划), 首先给出状态转移方程,设dp[i][j]表示用大小为j的背包去装前i个所能获得的最大价值, w[i]表示第i个物品的体积,v[i]表示第i个物品的价值。

关于第i个物品的决策,就是间单的”取与不取”,我们很容易得到如下的状态转移方程:dp[i][j]=max(dp[i-1][j], dp[i-1][j-w[i]]+v[i]);这边dp[i-1][j]表示第i个物品不取,dp[i-1][j-w[i]]+v[i]表示第i个物品取因为每次推导只用的到i-1维,我们其实可以只用一维的滚动数组就可以来求解。

这时候要逆序求解,这边不多做介绍接下来是打印路径问题,这个需要逆序贪心打印。

第i个背包是否选取应该用dp[i][V]与dp[i-1][V]来比较,从而求解,dp[i][V]>dp[i-1][V],V表示当前可存在的最大容量。

根据贪心,容量V越大价值同样装前i个一定更优,后面的推导的正解一定是基于dp[i][V]的,所以可以这么选标程如下:#include <stdio.h>#include <algorithm>using namespace std;int dp[110][1010];int n, c, ans[110];int w[110], v[110];void print(){int i, j, k;k=c;for(i=n; i>=1; i--){if(dp[i][k]!=dp[i-1][k]){ans[i]=1;k=k-w[i];}else{}}return;}int main(){int i, j, k;scanf("%d%d", &n, &c);for(i=1; i<=n; i++){scanf("%d%d", &w[i], &v[i]);}for(i=1; i<=n; i++){for(j=1; j<=c; j++){dp[i][j]=dp[i-1][j];if(j>=w[i]){dp[i][j]=max(dp[i-1][j-w[i]]+v[i], dp[i][j]);}}}printf("%d\n", dp[n][c]);print();for(i=1; i<=n; i++) {printf("%d\n", ans[i]);}return 0;}第二题:设有n种不同面值的硬币,各硬币的面值存于数组T[1:n]中。

DP类型各题总结-acm

DP类型各题总结-acm

最大连续子序列Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11540 Accepted Submission(s): 4856还需要输出该子序列的第一个和最后一个元素。

对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元素,中间用空格分隔。

如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。

若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

思路:一路加如果sum变成小于0了从当前位置重新新开始加(小于0的话就对整个段没有贡献了而且会使整个段的和变小)#include<stdio.h>int main(){int n,i,a[10005],start,end,sum,max,sta,flag,cnt;while(1){cnt=0;sum=0;max=-1;flag=1;scanf("%d",&n);if(n==0) return 0;for(i=0;i<n;i++){scanf("%d",&a[i]);if(a[i]<0) cnt++;if(a[i]==0) flag=0;}start=sta=end=a[0];if((cnt==n||cnt==n-1)){if(flag==0){printf("0 0 0\n"); continue;}elseif(n!=1){ printf("0 %d %d\n",a[0],a[n-1]);continue;}}for(i=0;i<n;i++){sum=sum+a[i];if(sum<0&&i+1<n){sta=a[i+1]; sum=0;}else{if(sum>max){max=sum;end=a[i];start=sta;}}}printf("%d %d %d\n",max,start,end);}}Hdu 1087 super jumping题意:此题就是找序列中最大升序子序列的和。

dp小结背包问题

dp小结背包问题

dp⼩结背包问题1.先放上0-1背包模板⼆维数组for(int i=1;i<=n;i++)//枚举物品for(int j=1;j<=V;j++)//枚举体积//这个位置是可以正序枚举的. qwq//⼀维01背包必须倒叙emmm//这个没错a emmmif(j>=c[i])f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);//状态转移⽅程.else f[i][j]=f[i-1][j].滚动⼆维数组int dp[2][10010];int row = 0; //滚动for (int i = 1; i < n; ++i) {row = 1 - row;for (int j = 1; j <= i * (i + 1) / 2; ++j) {//这⾥可以减少枚举if(j>=c[i])f[row][j]=max(f[1-row][j],f[1-row][j-c[i]]+w[i]);//状态转移⽅程.else f[row][j]=f[1-row][j].}}⼀维数组(逆序)for(int i=1;i<=n;i++)//枚举物品for(int j=V;j>=c[i];j--)//枚举体积f[j]=max(f[j],f[j-c[i]]+w[i]);//状态转移⽅程.模板题:“采药”这道题套模板就⾏了,从⼆维到⼀维优化。

2.顺便再复习记忆化搜索先想到dfs搜索暴⼒解题,就是多参数递归,出⼝记录搜索到的值再想到记忆化搜索,什么时记忆化搜索?记录每⼀次dfs答案,免去重复计算,从⽽起到优化时间复杂度的作⽤记忆化搜索记录什么值呢?记录每次搜索结束找到的价值(不⼀定最⼤)如何想到可以⽤记忆化搜索?3.蓝桥杯考过的记忆化搜索——使⽤四维数组缓存记录。

4.蓝桥杯考过的0-1背包:这道题⽐较难想到0-1背包,选数字对应成拿物品填充背包,dp[i][j]表⽰⽤前i个数凑出数字j的⽅案数,类似题⽬:我记得有⼀道选⼏个数字,凑出数字n。

简单dp问题汇总

简单dp问题汇总

简单dp问题汇总简单dp问题总共分为四类:找钱问题,01背包问题,最长公共⼦序列问题,最长递增⼦序列问题------------------------------------------------------------------------------------------------------------------------------------------找钱问题这类问题是dp中最基础的问题,其形式是最外层循环为钱的种类,第⼆层是钱的⾦额,最末层是⽤多少数量的钱实现但是核⼼是建⽴在后续能⽤前⾯的值推出的基础上。

dp[j][k] = dp[j][k] + dp[j - 1][k - money[i]];j表⽰⽤多少张钱,k表⽰⽬前的⾦额这种问题要先知道可⽤的钱币是什么,然后先把他存在数组⾥1 #include <iostream>2 #include <cstring>3using namespace std;4int money[5] = { 1,5,10,25,50 };5long long int dp[300][300] = {0};6int ans[300] = {0};7int main()8 {9int n;10 memset(dp, 0, sizeof(dp));11 dp[0][0] = 1;//切记是从dp[0][0]开始的12for (int i = 0; i < 5; i++)13 {14for (int j = 1; j <= 100; j++)15 {16for (int k = money[i]; k <252; k++)//之前开太⼤了,爆栈17 {18 dp[j][k] = dp[j][k] + dp[j - 1][k - money[i]];1920 }21 }22 }2324for (int i = 0; i <252; i++)25 {26 ans[i] = 0;27for (int j = 0; j <= 100; j++)28 {29 ans[i] += dp[j][i];30 }31 }32while (cin >> n) cout << ans[n] << endl;33return0;34 }------------------------------------------------------------------------------------------------------------------------------------------0/1背包问题这问题核⼼就是控制背包容量,然后问当前物品装还是不装的问题纵向是第⼏个物品横向是背包容量dp[j][k] = max(dp[j - 1][k], dp[j - 1][k - bone[j].volume] + bone[j].value);不装就和前⼀个情况⼀样,装就要在当前背包容量减去所要装的⾻头体积的情况下再加上此⾻头的价值附加:如果背包的数为⼩数,⽐如两位⼩数,则对每个数*100,把他提升为整数问题(hdu1864)1 #include <cstdlib>2 #include <cctype>3 #include <iterator>4 #include <vector>5 #include <cstring>6 #include <cassert>7 #include <map>8 #include <queue>9 #include <set>10 #include <stack>11 #include <stdio.h>12#define ll long long13#define INF 0x3f3f3f3f14#define ld long double15const ld pi = acos(-1.0L), eps = 1e-8;16using namespace std;17int dp[1010][1010];18struct Bone19 {20int value, volume;21 };22 Bone bone[1010];23int main()25 ios::sync_with_stdio(false);26 cin.tie(0);27int n;28 cin >> n;29for (int i = 1; i <= n; i++)30 {31 memset(dp, 0, sizeof(dp));32int num, volume;33 cin >> num >> volume;34for (int j = 1; j <= num; j++) cin >> bone[j].value;35for (int j = 1; j <= num; j++)cin >> bone[j].volume;3637for (int j = 1; j <= num; j++)38 {39for (int k = 0; k <= volume; k++)40 {41if (bone[j].volume > k)dp[j][k] = dp[j - 1][k];//如果当前⾻头都⽐被背包⼤的话,那肯定不能放进去的42else dp[j][k] = max(dp[j - 1][k], dp[j - 1][k - bone[j].volume] + bone[j].value);43 }44 }4546 cout << dp[num][volume] << endl;47 }48 }------------------------------------------------------------------------------------------------------------------------------------------最长公共⼦序列问题感觉这个可以背下来遍历⼀下,如果元素相同,就找dp[i-1][j-1]的那个值+1;否则就找dp[i][j-1]和dp[i-1][j]中最⼤的1 #include <iostream>2 #include <cmath>3 #include <algorithm>4 #include <cstring>5 #include <string>6using namespace std;7int dp[1005][1005];8string s1, s2;9int main()10 {1112while (cin >> s1 >> s2)13 {14 memset(dp, 0, sizeof(dp));15for (int i = 1; i <= s1.size(); i++)16 {17for (int j = 1; j <= s2.size(); j++)18 {19if (s1[i - 1] == s2[j - 1])20 {21 dp[i][j] = dp[i - 1][j - 1] + 1;22 }23else24 {25 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);26 }27 }28 }29 cout << dp[s1.size()][s2.size()] << endl;30 }31 }------------------------------------------------------------------------------------------------------------------------------------------最长递增⼦序列⽤两个循环定位第⼀个循环定位当前值i第⼆个循环依次循环j从开始到当前值,只要该值⽐当前固定的值(第⼀层循环)⼩,那么就检查以它为结尾的最长递增⼦序列长度是多少,找出最长的那个⼦序列长度,dp[i] = maxi + 1;1 #include <iostream>2using namespace std;3int st[10000];4int dp[10000] = { 0 };5int main()7int n;8 cin >> n;9for (int i = 1; i<=n; i++) cin >> st[i];10 dp[1] = 1;//第⼀个数最长只能为111int ans = 1;12for (int i = 2; i <= n; i++)13 {14int maxi = 0;15for (int j = 1; j < i; j++)16 {17if (dp[j] >maxi &&st[j]>st[i]) maxi = dp[j];18 }19 dp[i] = maxi + 1;//如果该数前⾯的数都不满⾜,那么他的长度就是1,从他⾃⼰开始20if (dp[i] > ans) ans = dp[i];//找出最⼤的21 }22 cout << ans << endl;23 }优化:可以添加⼀个辅助数组,来存最长递增⼦序列辅助数组先存⼊原数组的第⼀个,之后依次遍历原数组的每⼀个值如果原数组的当前遍历值⼤于辅助数组的最后⼀个值,那么当前遍历值直接加⼊辅助数组,更新辅助数组的最后⼀个值如果原数组的当前遍历值⼩于等于辅助数组的最后⼀个值,那么替换辅助数组中第⼀个⼤于等于该遍历值的值⽐如原数组 1 3 6 5那么辅助数组依次为 1/1,3/1,3,6/1,3,5最后最长递增⼦序列的长度即为辅助数组的⼤⼩代码:#include <iostream>#include <algorithm>#include <cstring>using namespace std;int num[100010],arr[100010];int main(){int n;while (cin >> n){memset(arr, 0, sizeof(arr));for (int i = 1; i <= n; i++){cin >> num[i];}arr[1] = num[1];int len = 1;for (int i = 2; i <= n; i++){if (num[i] > arr[len]){len++;arr[len] = num[i];}else{int j = lower_bound(arr+ 1, arr + len + 1, num[i]) - arr;arr[j] = num[i];}}cout << len << endl;}}。

acm动态规划总结

acm动态规划总结

acm动态规划总结.docACM动态规划总结引言动态规划(Dynamic Programming,简称DP)是一种算法设计技巧,用于解决具有重叠子问题和最优子结构特性的问题。

在ACM国际大学生程序设计竞赛(ACM International Collegiate Programming Contest,简称ACM-ICPC)中,动态规划是解决某些类型问题的有力工具。

本文档将总结动态规划的基本概念、常见问题类型、算法设计技巧以及在ACM竞赛中的应用。

动态规划的基本概念动态规划的定义动态规划是一种将复杂问题分解为更小的子问题,通过解决这些子问题来构建原问题解的方法。

它通常用于求解优化问题,即在所有可能的解决方案中找到最佳解。

动态规划的关键特性重叠子问题:问题可以分解为多个子问题,这些子问题会重复出现。

最优子结构:问题的最优解包含子问题的最优解。

无后效性:一旦子问题被解决,其解可以被存储并重复使用,而不需要重新计算。

动态规划的步骤识别子问题:将原问题分解为更小的子问题。

确定状态:定义状态变量,用于描述子问题的状态。

确定状态转移方程:找到状态之间的关系,即状态转移方程。

确定边界条件:确定问题的基本情况,为递推提供起点。

计算顺序:确定计算子问题的顺序,以避免重复计算。

构造最优解:根据存储的子问题解,构造原问题的最优解。

常见动态规划问题类型背包问题背包问题是一类典型的动态规划问题,包括0/1背包问题、完全背包问题和多重背包问题等。

字符串编辑问题字符串编辑问题,如最长公共子序列(LCS)和最短公共超串(SSS),可以通过动态规划求解。

矩阵路径问题矩阵路径问题,如矩阵最小路径和,可以通过动态规划找到从矩阵一角到另一角的最优路径。

计数问题计数问题,如数位DP、组合总数等,可以通过动态规划计算不同条件下的计数。

游戏问题游戏问题,如石头剪刀布、尼姆游戏等,可以通过动态规划求解获胜策略。

动态规划算法设计技巧记忆化搜索记忆化搜索是一种自顶向下的动态规划方法,通过递归函数和缓存已解决的子问题来避免重复计算。

DP背包问题学习笔记及系列练习题

DP背包问题学习笔记及系列练习题

DP背包问题学习笔记及系列练习题 01 背包: 01背包:在M件物品中取出若⼲件物品放到背包中,每件物品对应的体积v1,v2,v3,....对应的价值为w1,w2,w3,,,,,每件物品最多拿⼀件。

和很多DP题⼀样,对于每⼀个物品,都只有拿或者不拿这两种状态,不拿或者拿不动,dp[i][j]=dp[i-1][j],容量不变,⽽如果拿的话,为dp[i][j]=dp[i-1][j-w[i]]+v[i];所以总的来说:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]) 在⼆维的写法中,dp[ i ] [ j ]表⽰拿前 i 件物品去塞容积为 j 的背包可以得到的最⼤价值,所以最后dp[ n ][ v ]就是所求问题的答案。

b站某⼤佬做的。

要点全在动画演⽰⾥,要说这么解释,我觉得没什么必要,拿个例⼦,不要偷懒,拿笔把表填⼀下,绝对会豁然开朗! 上板⼦裸题#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn = 1e3+10;int dp[maxn][maxn];int w[maxn],v[maxn];int n,s;void ac ( ){for(int i=1 ;i<= n;i++){for(int j= 1 ;j<= s;j++ ){if(w[i]>j) //放不下{dp[i][j]=dp[i-1][j];}else{dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);}}}}int main(){cin>>n>>s;for(int i =1 ; i <= n; i ++){cin>>w[i]>>v[i];}ac();cout<<dp[n][s]<<endl;} 但是⼆维有时候会MLE,所以考虑⽤⼀个滚动数组来优化。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最大连续子序列Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11540 Accepted Submission(s): 4856还需要输出该子序列的第一个和最后一个元素。

对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元素,中间用空格分隔。

如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。

若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

思路:一路加如果sum变成小于0了从当前位置重新新开始加(小于0的话就对整个段没有贡献了而且会使整个段的和变小)#include<stdio.h>int main(){int n,i,a[10005],start,end,sum,max,sta,flag,cnt;while(1){cnt=0;sum=0;max=-1;flag=1;scanf("%d",&n);if(n==0) return 0;for(i=0;i<n;i++){scanf("%d",&a[i]);if(a[i]<0) cnt++;if(a[i]==0) flag=0;}start=sta=end=a[0];if((cnt==n||cnt==n-1)){if(flag==0){printf("0 0 0\n"); continue;}elseif(n!=1){ printf("0 %d %d\n",a[0],a[n-1]);continue;}}for(i=0;i<n;i++){sum=sum+a[i];if(sum<0&&i+1<n){sta=a[i+1]; sum=0;}else{if(sum>max){max=sum;end=a[i];start=sta;}}}printf("%d %d %d\n",max,start,end);}}Hdu 1087 super jumping题意:此题就是找序列中最大升序子序列的和。

可跳不一定非要连续比如 1 3 2 中升序序列有:{1}{3}{2}{1,3}{1,2}。

所以最大为1+3=4;#include<stdio.h>__int64 a[1005],sum[1005];int main(){int i,j,n,max,ans;while(scanf("%d",&n)&&n){for(i=0;i<n;i++) {scanf("%I64d",&a[i]);sum[i]=a[i];}ans=0;for(i=0;i<n;i++)//j比i小{for(j=0;j<i;j++){ if(a[j]<a[i]) sum[i]=sum[i]>(sum[j]+a[i])?sum[i]:(sum[j]+a[i]);//sum[j] 之前已经求出来了}ans=ans>sum[i]?ans:sum[i];}printf("%d\n",ans);}return 0;}Common SubsequenceTime Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)Total Submission(s) : 29 Accepted Submission(s) : 16Problem DescriptionA subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is a subsequence of X if there exists a strictly increasing sequence <i1, i2, ..., ik> of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.Sample Inputabcfbc abfcabprogramming contestabcd mnpSample Output42题意:求两个串的最长公共子序列用f [ i ][ j ]表示处理到字符串A的第i 位和字符串B第j位时的最大值。

状态转移方程如下:f [ i ][ j ] = f[ i - 1 ][ j - 1 ] + 1 (A[ i ] == B[ j ])f [ i ][ j ] = max( f[ i - 1 ][ j ], f [ i ][ j - 1] ) (A[ i ] != B[ j ])由于每次循环计算只和上一行状态有关,所以可以用循环数组压缩空间和背包中的一样哦#include<stdio.h>#include<string.h>char a[1000],b[1000];int dp[1000][1000];int d1,d2;int main(){int i,j;while(scanf("%s",a+1)!=EOF){scanf("%s",b+1);d1=strlen(a+1);d2=strlen(b+1);for(i=0;i<=d1;i++)dp[i][0]=0;for(j=0;j<=d2;j++)dp[0][j]=0;for(i=1;i<=d1;i++){for(j=1;j<=d2;j++)if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;else{dp[i][j]=dp[i-1][j]>dp[i][j-1]?dp[i-1][j]:dp[i][j-1];}}printf("%d\n",dp[d1][d2]);}return 0;}很好的hdu 1080 Human Gene Functions输入27 AGTGA TG5 GTTAG7 AGCTA TT9 AGCTTTAAA输出1421题意:两个字符串,每个字符串中都可以插入'-',保证最后两串的长度相等,之后让两串对齐,两串相同位置的字母组成的字符匹配有一个值,问这些值的和最大是多少,是第一题的变形下图为字符匹配所得价值的表dp[i][j]表示0到i-1跟0到j-1配对的最大价值状态转移:①dp[i][j]由dp[i-1][j]转移过来,代价是a[i-1]跟'-'匹配②由dp[i][j-1]转移过来,代价是b[j-1]跟'-'匹配③由dp[i-1][j-1]转移过来,代价是a[i-1]跟b[j-1]匹配、#include<stdio.h>#include<string.h>int max[500][500];int map[150][150];void match(){map['A']['A']=5;map['A']['C']=-1;map['A']['G']=-2;map['A']['T']=-1;map['A']['-']=-3;map['C']['A']=-1;map['C']['C']=5;map['C']['G']=-3;map['C']['T']=-2;map['C']['-']=-4;map['G']['A']=-2;map['G']['C']=-3;map['G']['G']=5;map['G']['T']=-2;map['G']['-']=-2;map['T']['A']=-1;map['T']['C']=-2;map['T']['G']=-2;map['T']['T']=5;map['T']['-']=-1;map['-']['A']=-3;map['-']['C']=-4;map['-']['G']=-2;map['-']['T']=-1;//map['-']['-']=-3; }int main(){int i,j,t,len1,len2;char q1[500],q2[500];match();scanf("%d",&t);while(t--){scanf("%d %s",&len1,q1+1);scanf("%d %s",&len2,q2+1);memset(max,0,sizeof(max));max[0][0]=0;for(i=1;i<=len1;i++)//max[i][0]=map[q1[i]]['-'];//哎这里初始化搞错了阿弥陀佛max[i][0]=max[i-1][0]+map[q1[i]]['-'];for(j=1;j<=len2;j++)// max[0][j]=map['-'][q2[j]];max[0][j]=max[0][j-1]+map['-'][q2[j]];for(i=1;i<=len1;i++)for(j=1;j<=len2;j++){max[i][j]=(max[i-1][j-1]+map[q1[i]][q2[j]])>(max[i-1][j]+map[q1[i]]['-'])?(max[i-1][j-1]+map[q1[i]][q2[j]]):(max[i-1][j]+map[q1[i]]['-']);max[i][j]=max[i][j]>(max[i][j-1]+map['-'][q2[j]])?max[i][j]:(max[i][j-1]+map['-'][q2[j]]);}printf("%d\n",max[len1][len2]);}return 0;}Hdu 2084有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。

相关文档
最新文档