动态规划初步------B3635 硬币问题和B3636 文字工作和B3637 最长上升子序列

B3635 硬币问题

题目描述

今有面值为 1、5、11 元的硬币各无限枚。

想要凑出 nn 元,问需要的最少硬币数量。

输入格式

仅一行,一个正整数 n。

输出格式

仅一行,一个正整数,表示需要的硬币个数。

输入输出样例

输入 #1

15

输出 #1

3

输入 #2

12

输出 #2

2

说明/提示

样例解释

对于样例数据 1,最佳方案是 15=5+5+5,使用到 3 枚硬币。

对于样例数据 2,最佳方案是 12=11 + 1,使用到 2 枚硬币。

数据规模与约定

对于100% 的数据,保证 n≤10^6。

解释:使用一维dp,就是在当前问题中寻找出他的子问题,找到最优解。

#include<iostream>
#include <vector>
#include <algorithm>
using namespace std; 
int a[1000006];//定义a[i]为:凑出i元最少要a[i]个硬币
//这是一维dp
int main()
{
	int n;
	cin>>n;
	a[0]=0;
	a[1]=1;
	a[5]=1;
	a[11]=1;//根据题意初始化只有三种硬币,1,5,11
	for(int i=2;i<=n;i++)//在凑出i元的时候,可以由凑出i-1元,i-5元,i-11元的硬币个数加上一个,那么就要找出这三种情况中的最小需要的硬币。
	{
		if(i-1>=0)//在寻找这三种凑硬币的个数是要注意,会在减去这三种硬币的时候出现负数,要进行判断。
		{
			a[i]=a[i-1]+1;
			if(i-5>=0)
			{
				a[i]=min(a[i-1],a[i-5])+1;
				if(i-11>=0)
				{
					a[i]=min(a[i-1],min(a[i-5],a[i-11]))+1;
				}
			}
		}
	}
	cout<<a[n];
	return 0;
}

B3636 文字工作

题目描述

机器猫要在电脑前打字。一共需要打 n 个字,但现在文档里只有一个字。

机器猫有两种操作可以做。假设现在已经有 x个字,机器猫可以选择:

  • 往文档最后加一个字。字数变成 x+1。
  • 把文档复制粘贴一遍。字数变成 2x。

问机器猫至少需要多少次操作,才能得到恰好 n个字。

输入格式

仅一行,一个正整数 n。

输出格式

仅一行,一个正整数,表示最少操作次数。

输入输出样例

输入 #1

16

输出 #1

4

输入 #2

5

输出 #2

3

说明/提示

样例解释

样例数据1,1→2→4→8→16,共 4 步。

样例数据2,1→2→4→5,共 3 步。

数据规模与约定

对于 100\%100% 的数据,n≤10^6。

#include<iostream>
#include <algorithm>
using namespace std; 
int a[1000006];
int main()
{
	int n;
	cin>>n;
	a[1]=0;//对dp数组进行初始化,题目说开始的时候已经有一个字了
	for(int i=2;i<=n;i++)//根据题意建立状态转移方程式,得到i个字可以由两种方式得到,i-1和i/2个字加1
	{
		if(i%2==0)
		{
			a[i]=min(a[i-1],a[i/2])+1;
		}
		else
		{
			a[i]=a[i-1]+1;
		}
	} 
//	for(int i=1;i<=n;i++)
//	{
//		cout<<a[i]<<"\n";
//	}
	cout<<a[n];
	return 0;
}

B3637 最长上升子序列

题目描述

这是一个简单的动规板子题。

给出一个由 nn(n≤5000) 个不超过 10^6的正整数组成的序列。请输出这个序列的最长上升子序列的长度。

最长上升子序列是指,从原序列中按顺序取出一些数字排在一起,这些数字是逐渐增大的。

输入格式

第一行,一个整数 nn,表示序列长度。

第二行有 nn 个整数,表示这个序列。

输出格式

一个整数表示答案。

输入输出样例

输入 #1

6
1 2 4 1 3 4

输出 #1

4

说明/提示

分别取出 1、2、3、4 即可。

#include<iostream>
#include <algorithm>
using namespace std; 
int a[5003];
int c[5003];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	c[1]=1;
	for(int i=2;i<=n;i++)//找状态转移方程式c[i]:在数组中a[i]中以第i个元素结尾的最长上升子序列
	{
		int t=0;
		for(int j=1;j<i;j++)//在前j个元素中,找小于a[i]的以a[j]结尾的最大值,然后再加1。
		{
			if(a[i]>a[j])
			{
				t=max(c[j],t);
			}
		}
		c[i]=t+1;
	}
	int max1=0;
	for(int i=1;i<=n;i++)//找出最大值
	{
		max1=max(max1,c[i]);
	}
	cout<<max1;
	return 0;
}

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ssssss555555777777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值