基础动态规划:
例题 a n d and and 代码:
大盗阿福
题目描述
阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。
这条街上一共有 N 家店铺,每家店中都有一些现金。阿福事先调查得知,只有当他同时洗劫了两家相邻的店铺时,街上的报警系统才会启动,然后警察就会蜂拥而至。
作为一向谨慎作案的大盗,阿福不愿意冒着被警察追捕的风险行窃。他想知道,在不惊动警察的情况下,他今晚最多可以得到多少现金?
输入格式
输入的第一行是一个整数 T (T <= 50) ,表示一共有 T 组数据。
接下来的每组数据,第一行是一个整数 N (1 <= N <= 100, 000) ,表示一共有 N 家店铺。第二行是 N 个被空格分开的正整数,表示每一家店铺中的现金数量。每家店铺中的现金数量均不超过 1000 。
输出格式
对于每组数据,输出一行。该行包含一个整数,表示阿福在不惊动警察的情况下可以得到的现金数量。
样例 #1
样例输入 #1
2
3
1 8 2
4
10 7 6 14
样例输出 #1
8
24
提示
对于第一组样例,阿福选择第 2 家店铺行窃,获得的现金数量为 8 。
对于第二组样例,阿福选择第 1 和 4 家店铺行窃,获得的现金数量为 10 + 14 = 24 。
A C AC AC 代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int dp[N][2];
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
int x;
for(int i=1;i<=n;i++){
cin>>x;
dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
dp[i][1]=dp[i-1][0]+x;
}
cout<<max(dp[n][0],dp[n][1])<<endl;
}
return 0;
}
[USACO08FEB] D i n i n g C o w s B Dining Cows B DiningCowsB
题目描述
为了避免餐厅过分拥挤,FJ要求奶牛们分2批就餐。每天晚饭前,奶牛们都会在餐厅前排队入内,按FJ的设想,所有第2批就餐的奶牛排在队尾,队伍的前半部分则由设定为第1批就餐的奶牛占据。由于奶牛们不理解FJ的安排,晚饭前的排队成了一个大麻烦。 第i头奶牛有一张标明她用餐批次D_i(1 <= D_i <= 2)的卡片。虽然所有N头奶牛排成了很整齐的队伍,但谁都看得出来,卡片上的号码是完全杂乱无章的。 在若干次混乱的重新排队后,FJ找到了一种简单些的方法:奶牛们不动,他沿着队伍从头到尾走一遍,把那些他认为排错队的奶牛卡片上的编号改掉,最终得到一个他想要的每个组中的奶牛都站在一起的队列,例如112222或111122。有的时候,FJ会把整个队列弄得只有1组奶牛(比方说,1111或222)。 你也晓得,FJ是个很懒的人。他想知道,如果他想达到目的,那么他最少得改多少头奶牛卡片上的编号。所有奶牛在FJ改卡片编号的时候,都不会挪位置。
输入格式
第1行: 1个整数:N * 第2…N+1行: 第i+1行是1个整数,为第i头奶牛的用餐批次D_i
输出格式
一行: 输出1个整数,为FJ最少要改几头奶牛卡片上的编号,才能让编号变成他设想中的样子。
样例 #1
样例输入 #1
7
2
1
1
1
2
2
1
样例输出 #1
2
样例 #2
样例输入 #2
5
2
2
1
2
2
样例输出 #2
1
提示
1 <= N <= 30000
A C AC AC 代码
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int dp[N][3];
int main(){
int n;
cin>>n;
int x;
for(int i=1;i<=n;i++){
cin>>x;
dp[i][2]=min(dp[i-1][1],dp[i-1][2])+(x==1);
dp[i][1]=dp[i-1][1]+(x==2);
}
cout<<min(dp[n][1],dp[n][2])<<endl;
return 0;
}
动态规划经典例题 动态规划经典例题 动态规划经典例题 最长上升子序列
题目描述
这是一个简单的动规板子题。
给出一个由 n ( n ≤ 5000 ) n(n\le 5000) n(n≤5000) 个不超过 1 0 6 10^6 106 的正整数组成的序列。请输出这个序列的最长上升子序列的长度。
最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。
输入格式
第一行,一个整数 n n n,表示序列长度。
第二行有 n n n 个整数,表示这个序列。
输出格式
一个整数表示答案。
样例 #1
样例输入 #1
6
1 2 4 1 3 4
样例输出 #1
4
提示
分别取出 1 1 1、 2 2 2、 3 3 3、 4 4 4 即可。
A C AC AC 代码
#include <bits/stdc++.h>
using namespace std;
int a[5005],n,dp[5005];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++){
if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1);
}
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
return 0;
}
最长奇数不升子序列
题目描述
给定序列,求出最长不上升子序列,且子序列中的每一元素均为奇数。
输入格式
输入的第一行是序列的长度N (1 <= N <= 1000)。
第二行给出序列中的N个整数,这些整数的绝对值范围都在0到10000之间。
输出格式
一行,一个整数,表示最长奇数不升子序列的长度。
样例 #1
样例输入 #1
7
1 7 3 5 9 4 8
样例输出 #1
2
样例 #2
样例输入 #2
5
0 3 3 1 9
样例输出 #2
3
样例 #3
样例输入 #3
10
9 9 9 8 8 7 7 6 6 4
样例输出 #3
5
提示
对于样例2,最优序列为{3 3 1}。
对于样例3,最优序列为{9 9 9 7 7}
A C AC AC 代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int a[N],dp[N],n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
if(a[i]%2==1) dp[i]=1;
for(int j=1;j<=i-1;j++){
if(a[i]<=a[j]&&a[i]%2!=0&&a[j]%2!=0){
dp[i]=max(dp[i],dp[j]+1);
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i]);
}
cout<<ans;
return 0;
}
[NOIP2004 提高组] 合唱队形
题目描述
n n n 位同学站成一排,音乐老师要请其中的 n − k n-k n−k 位同学出列,使得剩下的 k k k 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 k k k 位同学从左到右依次编号为 1 , 2 , 1,2, 1,2, … , k ,k ,k,他们的身高分别为 t 1 , t 2 , t_1,t_2, t1,t2, … , t k ,t_k ,tk,则他们的身高满足 t 1 < ⋯ < t i > t i + 1 > t_1< \cdots <t_i>t_{i+1}> t1<⋯<ti>ti+1> … > t k ( 1 ≤ i ≤ k ) >t_k(1\le i\le k) >tk(1≤i≤k)。
你的任务是,已知所有 n n n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
共二行。
第一行是一个整数 n n n( 2 ≤ n ≤ 100 2\le n\le100 2≤n≤100),表示同学的总数。
第二行有 n n n 个整数,用空格分隔,第 i i i 个整数 t i t_i ti( 130 ≤ t i ≤ 230 130\le t_i\le230 130≤ti≤230)是第 i i i 位同学的身高(厘米)。
输出格式
一个整数,最少需要几位同学出列。
样例 #1
样例输入 #1
8
186 186 150 200 160 130 197 220
样例输出 #1
4
提示
对于 50 % 50\% 50% 的数据,保证有 n ≤ 20 n \le 20 n≤20。
对于全部的数据,保证有 n ≤ 100 n \le 100 n≤100。
A C AC AC 代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e2+5;
int dp[N][2],a[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
dp[i][0]=dp[i][1]=1;
for(int j=1;j<i;j++){
if(a[i]<a[j]) dp[i][0]=max(dp[i][0],max(dp[j][0],dp[j][1])+1);
else if(a[i]>a[j]) dp[i][1]=max(dp[i][1],dp[j][1]+1);
}
}
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,max(dp[i][0],dp[i][1]));
cout<<n-ans<<endl;
return 0;
}