简单dp&递推合集
来源:互联网 发布:json数组转换java对象 编辑:程序博客网 时间:2024/06/01 14:29
以下题目全部来自EOJ。
1075 庆祝迎评成功
一个蛋糕切n刀,求最多可以切成几块。
说明
对三维问题,降维处理不失为一种好方法。我们先考虑二维情况:
- n条直线分割一个平面,最多可以分割成几块?
假设n-1条直线已经确定(并且已经是最优解,下同),那么第n条直线需要与前n-1条直线交于n-1个不同的点,这使第n条直线被分为n份,平面则将被多分出n个区域。
我们设二维情况的答案为f(n),则f(n)=f(n-1)+n,推得通项公式f(n)=1+n(n+1)/2。
推广到三维,设此时答案为s(n)。n-1个平面已经确定,第n个平面需要与前n-1个平面有n-1条交线,这使第n个平面被分为f(n-1)份,空间则将被多分出f(n-1)个区域。我们得到:s(n)=s(n-1)+f(n-1)=s(n-1)+1+n(n-1)/2。
边界条件为s(0)=1。
#include <stdio.h>int main(){ int a, i; long long s[1001]; s[0] = 1; for (i = 1; i < 1001; ++i) s[i] = s[i - 1] + i * (i - 1) / 2 + 1; while (scanf("%d", &a) && a) printf("%lld\n", s[a]); return 0;}
1015 核电站
一个核电站有 N 个放核物质的坑,坑排列在一条直线上。
如果连续 M 个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质。
任务:对于给定的 N 和 M,求不发生爆炸的放置核物质的方案总数
说明
设第n个坑不发生爆炸的方案数为发f(n),我们假设前n-1个坑已经确定。分两种情况:
- 已经有连续m-1个核物质,那么第n个坑只能不放核物质,且者m-1个坑前的那个坑也不能放核物质。方案数为f((n-1)-(m-1)-1)=f(n-m-1)。
- 否则,第n个坑可以选择放或不放。方案数为2*[f(n-1)-f(n-m-1)]。
边界条件f(0)=1。
具体计算时可以用dp的递推形式写,也可以像如下代码中用2的幂计算:
#include <stdio.h>#include <math.h>int main(void){ int n, m, i; long long nuc[60]; nuc[0] = 1; while (~scanf("%d%d", &n, &m)){ for (i = 1; i <= 50; ++i){ if (i < m) nuc[i] = (long long)pow(2, i); else if(i == m) nuc[i] = (long long)pow(2, m) - 1; else nuc[i] = 2 * nuc[i - 1] - nuc[i - m - 1]; } printf("%I64d\n", nuc[n]); } return 0;}
(注:这里不能预处理nuc数组,因为m未知)
3267 足球锦标赛
计分板上的每一位都按顺序挂了 0 到 9 这 10 个牌子,所以可以表示 000 至 999。当其中一个队的得分从 010 变成 011 时,计分员只要将最后一位的最前面的牌子向后翻即可,共需翻动一块牌子;当得分从 019 变成 020 是,由于 9 后面已经没有牌子了,所以计分员要将 0 到 9 全部翻到前面,并将倒数第二位的牌子 1 翻到后面,所以共需翻动 10 块牌子。
现场的计分牌和图中所示还是存在差异的,现场的计分牌会很大,很重,所以翻每块牌子都要消耗 1 点体力。
你是计分员,现在比赛还剩下最后十分钟。现在有一个预言家告诉你在这十分钟里,双方得分共计多少;但他没有告诉你双方得分各是多少。所以你想要知道你要花费的体力值最多是多少。
说明
先模拟翻牌,预处理记录体力的数组。然后枚举双方得分情况,求最大值。
#include <stdio.h>int dp[1001]={0};void init(){ int i; for (i = 1; i <= 999; ++i){ if (i % 100 == 0) dp[i] = dp[i - 1] + 19; else if (i % 10 == 0) dp[i] = dp[i - 1] + 10; else dp[i] = dp[i - 1] + 1; } return;}int main(void){ int t, i, a, b, sc, j; scanf("%d", &t); init(); for (i = 1; i <= t; ++i){ scanf("%3d %3d %d", &a, &b, &sc); int ans = 0, now = 0; for (j = 0; j <= sc; ++j){ now = dp[a + j] - dp[a] + dp[b + sc - j] - dp[b]; if (now > ans) ans = now; } printf("Case %d: %d\n", i, ans); } return 0;}
1052 0-1背包问题
已知 n 个物体 1,2,3,…,n 与一个背包。物体 i 的重量为 Wi>0,价值为 Pi>0 (i=1,2,…,n),背包容量为 M>0。
求在不超过背包容量的情况下,使得装进去的物体的价值最高。
说明
经典入门dp题。用一维数组实现时需要注意j需要从m到w递减,这与动规的bottom-up思路是一致的。
#include<stdio.h>int main(){ int t; scanf("%d", &t); while(t--) { int n, m, i, j, w, v, a[100001] = {0}; scanf("%d%d", &n, &m); for(i = 0; i < n; ++i){ scanf("%d%d", &w, &v); for(j = m; j >= w; --j) if (a[j - w] + v > a[j]) a[j] = a[j - w] + v; } printf("%d\n",a[m]); } return 0;}
3302 打印
打印 n 个相同的字符,插入或删除一个字符花费的时间为 x,复制当前整个文本并且粘贴在后面的时间花费为 y,求完成 n 个字符的打印所需的最小花费时间。
说明
dp[i]表示打印i个字符需要的最小时间。
- i为偶数时,可能是(i-1个字符+插入一个字符)/(i/2个字符复制一次)两种操作之一产生的,取它们的最小值。
- i为奇数时,可能是(i-1个字符+插入一个字符)/((i+1)/2个字符复制一次)两种操作之一产生的,取它们的最小值。
写的时候用的c,还并不会定义宏,导致代码看起来比较繁琐。
#include <stdio.h>#include <memory.h>#define MAX 10000001typedef long long LL;LL dp[MAX];LL printing(int n, int x, int y){ int i; if (n == 0) return 0; if (n == 1) return x; memset(dp, 0, sizeof(dp)); for (i = 1; i <= n; ++i){ if (i % 2) dp[i] = (dp[i-1]+x < dp[(i+1)/2]+y+x)?dp[i-1]+x:dp[(i+1)/2]+y+x; else dp[i] = (dp[i-1]+x < dp[i/2]+y)?dp[i-1]+x:dp[i/2]+y; } return dp[n];}int main(){ int n,x,y; scanf("%d%d%d",&n, &x, &y); LL ans = printing(n, x, y); printf("%lld", ans); return 0;}
- 简单dp&递推合集
- 简单DP
- 简单dp
- 简单dp
- 简单DP
- 简单dp
- 简单DP
- 简单?dp
- 简单dp
- 简单dp
- 简单DP
- 简单DP
- 简单dp
- dp专题2--简单dp
- PKU3356 AGTC (简单DP)
- POJ2192 Zipper(简单DP)
- HDU 1087 简单DP
- zoj 2402 简单dp
- 在xml中添加<!DOCTYPE >节点
- Redis入门很简单之六【Jedis常见操作】
- PADS LOGIC-->AD-->ORCAD CAPTURE
- 剑指offer 编程题(33):第一个只出现一次的字符
- 审批流程系统详细设计
- 简单dp&递推合集
- bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA
- 跨域问题(转:最近太忙啦!!!)
- Android 程序运行后,界面不显示的问题解决办法
- [android]在 Html.fromHtml 中的换行被忽略
- 一:函数模板(Function Template)
- spring系列(七):SSH整合二
- hihocoder#1347 : 小h的树上的朋友(树链剖分)
- vimtutor笔记