简单 dp
1.摆花问题
题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆。通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号。为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入
输入共2行。
第一行包含两个正整数n和m,中间用一个空格隔开。
第二行有n个整数,每两个整数之间用一个空格隔开,依次表示a1、a2、……an。
输出
输出只有一行,一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对1000007取模的结果。
样例输入
2 4
3 2
样例输出
2
提示
样例说明:
有2种摆花的方案,分别是(1,1,1,2),(1,1,2,2)。括号里的1和2表示两种花,比如第一个方案是前三个位置摆第一种花,第四个位置摆第二种花。
对于20%数据,有0<n≤8,0<m≤8,0≤ai≤8;
对于50%数据,有0<n≤20,0<m≤20,0≤ai≤20;
对于100%数据,有0<n≤100,0<m≤100,0≤ai≤100。
代码:
#include <bits/stdc++.h>
using namespace std; const int mod = ;
int N, M;
int a[];
int dp[][]; int main() {
scanf("%d%d", &N, &M);
for(int i = ; i <= N; i ++)
scanf("%d", &a[i]); // 不管放多少盆花 如果只有一种那么方案书一定是 1
for(int i = ; i <= a[]; i ++)
dp[][i] = ; for(int i = ; i <= N; i ++) {
for(int j = ; j <= M; j ++) {
for(int k = ;k <= min(a[i], j); k ++)
dp[i][j] = (dp[i][j] + dp[i - ][j - k]) % mod;
}
} printf("%d\n", dp[N][M]);
return ;
}
简单 dp dp[i][j] 表示摆了前 i 种花一共摆了 j 盆的方案数
2.合唱队问题
描述
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1<=i<=K)。 你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
输入的第一行是一个整数N(2<=N<=100),表示同学的总数。第一行有n个整数,用空格分隔,第i个整数Ti(130<=Ti<=230)是第i位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
样例输入
8
186 186 150 200 160 130 197 220
样例输出
4
代码:
#include <bits/stdc++.h>
using namespace std; int N;
int a[], b[];
int l[], r[]; int main() {
scanf("%d", &N);
for(int i = ; i < N; i ++) {
scanf("%d", &a[i]);
b[i] = a[i];
} for(int i = ; i <= N / ; i ++)
swap(a[i], a[N - - i]); for(int i = ; i < N; i ++) {
for(int j = ; j < i; j ++)
if(b[i] > b[j])
l[i] = max(l[i], l[j] + );
} for(int i = ; i < N; i ++) {
for(int j = ; j < i; j ++)
if(a[i] > a[j])
r[i] = max(r[i], r[j] + );
} int ans = ;
for(int i = ; i < N; i ++)
ans = max(l[i] + r[i] - , ans); printf("%d\n", N - ans);
return ;
}
正向反向求最长严格上升子序列枚举中间点 i 因为 i 被算了两次是重复的所以要减去 1
3.方格取数
题目描述
设有N×N的方格图(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
某人从图的左上角的AA点出发,可以向下行走,也可以向右走,直到到达右下角的BB点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从(0, 0)点到(n,n)点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入:
8
6 1 7
3 2 9
2 3 5
1 4 3
3 4 3
6 6 6
1 7 1
0 0 0
输出:
67
代码:
#include <bits/stdc++.h>
using namespace std; int N;
int mp[][];
int dp[][][][]; int main() {
scanf("%d", &N);
int x, y, z;
while(~scanf("%d%d%d", &x, &y, &z)) {
if(!x && !y && !z) break;
mp[x][y] = z;
} for(int i = ; i <= N; i ++)
for(int j = ; j <= N; j ++)
for(int k = ; k <= N; k ++)
for(int l = ; l <= N; l ++) {
dp[i][j][k][l] = max(max(dp[i - ][j][k - ][l], dp[i][j - ][k][l - ]),
max(dp[i - ][j][k][l - ],dp[i][j - ][k - ][l]))+mp[i][j]; if(i != k || j != l) dp[i][j][k][l] += mp[k][l];
} printf("%d\n", dp[N][N][N][N]);
return ;
}
两个同时走 四维 dp 时间复杂度 $O(N^4)$ 还有一个时间复杂度为 $O(N^3)$ 的写法
4.乘积最大
题目描述:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积最大。例如,数字串为312,当N=3,K=1时会有以下两种分法:3*12=36和31*2=62,符合题目要求的结果为31*2=62。程序的输入共有两行:第一行共有两个自然数N、K(6<=N<=40,1<=K<=6),第二行是一个长度为N的数字串,输出一个整数,表示求得的最大乘积。
输入格式
第 1 行为整数 n,n≤50。
第 2 行为整数 k,k≤10。
第 3 行为数字字符串。
输出格式
一行一个数,表示最大的乘积。
输入样例
6
3
310143
输出样例
3720
代码:
#include <bits/stdc++.h>
using namespace std; int N, K;
string s;
int dp[][];
int num[][]; int main() {
scanf("%d%d", &N, &K);
cin >>s; memset(dp, , sizeof(dp));
for(int i = ; i < N; i ++) {
int sum = ;
for(int j = i; j < N; j ++) {
sum = sum * + (s[j] - '');
num[i][j] = sum;
}
} for(int i = ; i < N; i ++)
dp[i][] = num[][i]; for(int i = ; i < N; i ++)
for(int j = ; j <= K; j ++)
for(int k = ; k < i; k ++)
dp[i][j] = max(dp[k][j - ] * num[k + ][i], dp[i][j]); printf("%d\n", dp[N - ][K]);
return ;
}
dp[i][j] 代表的是在 s[0] 到 s[i] 的字符串中插入 j 个乘号最大乘积 num[i][j] 代表 以 s[i] 开始以 s[j] 结尾的数字大小 状态转移方程为 $dp[i][j] = max(dp[k][j - 1] * num[k + 1][i], dp[i][j])$
5.书的抄写
Description
有M本书(编号为1,2,…,M),每本书都有一个页数(分别是P1,P2,…,PM)。想将每本都复制一份。将这M本书分给K个抄写员(1<=K<=M<=500),每本书只能分配给一个抄写员进行复制。每个抄写员至少被分配到一本书,而且被分配到的书必须是连续顺序的。复制工作是同时开始进行的,并且每个抄写员复制一页书的速度都是一样的。所以,复制完所有书稿所需时间取决于分配得到最多工作的那个抄写员的复制时间。试找一个最优分配方案,使分配给每一个抄写员的页数的最大值尽可能小。
Input
第一行两个整数M、K;(K<=M<=500)
第二行M个整数,第i个整数表示第i本书的页数。
Output
1.输出为一个数,即分配给每一个抄写员的页数的最大值
2.共 K 行,每行 2 个正整数,第 i 行表示第 i 个人抄写的书的起始编号和终止编号,每两个数之间用一个空格隔开。K 行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写
Sample Input
9 3
1 2 3 4 5 6 7 8 9
Sample Output
1.
17
2.
1-5 (15页)
6-7 (13页)
8-9 (17页)
代码:
#include <bits/stdc++.h>
using namespace std; #define inf 0x3f3f3f3f
int N, K;
int p[], sum[];
int dp[][]; int main() {
scanf("%d%d", &N, &K); memset(sum, , sizeof(sum));
for(int i = ; i <= N; i ++) {
scanf("%d", &p[i]);
sum[i] = sum[i - ] + p[i];
} memset(dp, inf, sizeof(dp));
for(int i = ; i <= K; i ++) {
for(int j = i; j <= N; j ++) {
if(i == ) dp[i][j] = sum[j];
else {
for(int k = i - ; k <= j - ; k ++)
dp[i][j] = min(max(dp[i - ][k], sum[j] - sum[k]), dp[i][j]);
}
}
} printf("%d\n", dp[K][N]);
return ;
}
dp[i][j] 代表 i 个人 抄写 j 本书耗时最短 代码是输出 1 的结果 输出 2 不会 :-(
被 dp 折磨的一上午 开发智力???想豁奶茶了
简单 dp的更多相关文章
- HDU 1087 简单dp,求递增子序列使和最大
Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
- Codeforces Round #260 (Div. 1) A. Boredom (简单dp)
题目链接:http://codeforces.com/problemset/problem/455/A 给你n个数,要是其中取一个大小为x的数,那x+1和x-1都不能取了,问你最后取完最大的和是多少. ...
- codeforces Gym 100500H A. Potion of Immortality 简单DP
Problem H. ICPC QuestTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/a ...
- 简单dp --- HDU1248寒冰王座
题目链接 这道题也是简单dp里面的一种经典类型,递推式就是dp[i] = min(dp[i-150], dp[i-200], dp[i-350]) 代码如下: #include<iostream ...
- poj2385 简单DP
J - 简单dp Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:65536KB 64bit ...
- hdu1087 简单DP
I - 简单dp 例题扩展 Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:32768KB ...
- poj 1157 LITTLE SHOP_简单dp
题意:给你n种花,m个盆,花盆是有顺序的,每种花只能插一个花盘i,下一种花的只能插i<j的花盘,现在给出价值,求最大价值 简单dp #include <iostream> #incl ...
- hdu 2471 简单DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2571 简单dp, dp[n][m] +=( dp[n-1][m],dp[n][m-1],d[i][k ...
- Codeforces 41D Pawn 简单dp
题目链接:点击打开链接 给定n*m 的矩阵 常数k 以下一个n*m的矩阵,每一个位置由 0-9的一个整数表示 问: 从最后一行開始向上走到第一行使得路径上的和 % (k+1) == 0 每一个格子仅仅 ...
- poj1189 简单dp
http://poj.org/problem?id=1189 Description 有一个三角形木板,竖直立放.上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1).每颗钉子和周 ...
随机推荐
- 苏州Uber优步司机奖励政策(4月22日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 12 stark组件之pop,按钮,url,页面
1.Window open() 方法 http://www.runoob.com/jsref/met-win-open.html 效果图 2.admin的pop添加按钮 3.stark之pop功能 ...
- Codeforces 909E. Coprocessor (拓扑、模拟)
题目链接: Coprocessor 题意: 给出n个待处理的事件(0 - n-1),再给出了n个标(0表示只能在主处理器中处理这个事件,1表示只能在副处理器中处理这个事件),处理器每次能处理多个任务. ...
- 所有权链(Ownership Chain)
所有权链(Ownership Chain)是特殊的权限评估方式,常见拥有所有权的数据库对象是:数据库对象,数据库角色(Role),和架构(Schema),在创建数据库角色,或架构时,SQL Serve ...
- flask 实现异步非阻塞----gevent
我们都知道,flask不支持异步非阻塞的请求,我们可以创建一个新项目去测试一下,推荐大家使用pycharm去开发我们的flask 使用特别的方便. rom flask import Flask im ...
- alibaba/fescar 阿里巴巴 开源 分布式事务中间件
Fescar 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题. 示例:https://github.com/windwant/ ...
- Flink 部署文档
Flink 部署文档 1 先决条件 2 下载 Flink 二进制文件 3 配置 Flink 3.1 flink-conf.yaml 3.2 slaves 4 将配置好的 Flink 分发到其他节点 5 ...
- trustbox文件破解
常见的破解方式,是要还原内容的二进制文件,删除加密壳部分的对应二进制数值,然后把剩下的内容保存下来,就实现了破解的任务. 淘宝破解链接:https://item.taobao.com/item.ht ...
- split命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/lkforce/article/details/71547313 Linux中的文件,特别是日志文件,特别大了不好打开,可以 ...
- OGG 问题
1.启动复制时报 "ERROR OGG-15050 Oracle GoldenGate Delivery, l***.prm: Error loading Java VM runtime l ...