爱思创 算法夺奖专题班 L8 动态规划1 例题 and 代码

基础动态规划:

例题 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(n5000) 个不超过 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 nk 位同学出列,使得剩下的 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(1ik)

你的任务是,已知所有 n n n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入格式

共二行。

第一行是一个整数 n n n 2 ≤ n ≤ 100 2\le n\le100 2n100),表示同学的总数。

第二行有 n n n 个整数,用空格分隔,第 i i i 个整数 t i t_i ti 130 ≤ t i ≤ 230 130\le t_i\le230 130ti230)是第 i i i 位同学的身高(厘米)。

输出格式

一个整数,最少需要几位同学出列。

样例 #1
样例输入 #1
8
186 186 150 200 160 130 197 220
样例输出 #1
4
提示

对于 50 % 50\% 50% 的数据,保证有 n ≤ 20 n \le 20 n20

对于全部的数据,保证有 n ≤ 100 n \le 100 n100

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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值