动态规划235

# 疯狂的采药

## 题目背景

此题为纪念 LiYuxiang 而生。

## 题目描述

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

$1$. 每种草药可以无限制地疯狂采摘。

$2$. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

## 输入格式

输入第一行有两个整数,分别代表总共能够用来采药的时间 $t$ 和代表山洞里的草药的数目 $m$。

第 $2$ 到第 $(m + 1)$ 行,每行两个整数,第 $(i + 1)$ 行的整数 $a_i, b_i$ 分别表示采摘第 $i$ 种草药的时间和该草药的价值。

## 输出格式

输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

## 样例 #1

### 样例输入 #1

```
70 3
71 100
69 1
1 2
```

### 样例输出 #1

```
140
```

## 提示

#### 数据规模与约定

- 对于 $30\%$ 的数据,保证 $m \le 10^3$ 。
- 对于 $100\%$ 的数据,保证 $1 \leq m \le 10^4$,$1 \leq t \leq 10^7$,且 $1 \leq m \times t \leq 10^7$,$1 \leq a_i, b_i \leq 10^4$。

就是01背包

#include 
long long dp[10000001];
int time[10000001],money[10000001];
long long max(long long a,long long b)
{
	if(a>b) return a;
	else return b;
}
int main()
{
	int i,j;
	int t,m;
	scanf("%d%d",&t,&m);
	for(i=1;i<=m;i++)
	{
		scanf("%lld%lld",&time[i],&money[i]);
	}
	for(i=1;i<=m;i++)
	{
		for(j=time[i];j<=t;j++)
		{
			dp[j]=max(dp[j],dp[j-time[i]]+money[i]);
		}
	}
	printf("%lld",dp[t]);
}

# [USACO1.5][IOI1994]数字三角形 Number Triangles

## 题目描述

观察下面的数字金字塔。


写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

```cpp
        7 
      3   8 
    8   1   0 
  2   7   4   4 
4   5   2   6   5 
```
在上面的样例中,从 $7 \to 3 \to 8 \to 7 \to 5$ 的路径产生了最大

## 输入格式

第一个行一个正整数 $r$ ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

## 输出格式

单独的一行,包含那个可能得到的最大的和。

## 样例 #1

### 样例输入 #1

```
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```

### 样例输出 #1

```
30
```

## 提示

【数据范围】  
对于 $100\%$ 的数据,$1\le r \le 1000$,所有输入在 $[0,100]$ 范围内。

题目翻译来自NOCOW。

USACO Training Section 1.5

IOI1994 Day1T1

逆向求解

若从倒数第二排的‘2’开始走,只有2个选择,往左下方和右下方。

往左下方是‘4’,得到的最终值为6,往右下方是‘5’,得到的最终值是7.这时当然选择右下方。

我们就将‘2’改写成2+5=7。 再次考虑倒数第二排的7,

同理,应选择左下,得到最终值是12。还是将‘7’改写成5+7=12。

#include 
int max(int x,int y)
{
	if(x>y) return x;
	else return y;
}
int main()
{
	int i,j,teap;
	int n;
	int a[1001][1001];
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=i;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(i=n-1;i>=1;i--)
	{
		for(j=1;j<=i;j++)
		{
			teap=max(a[i+1][j],a[i+1][j+1]);
			a[i][j]=a[i][j]+teap;
		}
	}
	printf("%d",a[1][1]);
}

# 【模板】最长公共子序列

## 题目描述

给出 $1,2,\ldots,n$ 的两个排列 $P_1$ 和 $P_2$ ,求它们的最长公共子序列。

## 输入格式

第一行是一个数 $n$。

接下来两行,每行为 $n$ 个数,为自然数 $1,2,\ldots,n$ 的一个排列。

## 输出格式

一个数,即最长公共子序列的长度。

## 样例 #1

### 样例输入 #1

```

3 2 1 4 5
1 2 3 4 5
```

### 样例输出 #1

```
3
```

## 提示

- 对于 $50\%$ 的数据, $n \le 10^3$;
- 对于 $100\%$ 的数据, $n \le 10^5$。

动态规划

#include 
int a[100001],b[100001];
int s[100001];
int dp[100001];
int max(int a,int b)
{
	if(a>b) return a;
	else return b;
}
int main()
{
	int len=0;
	int i,j;
	int n;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		s[a[i]]=i;
	}
	for(i=1;i<=n;i++)
	{
		scanf("%d",&b[i]);
		b[i]=s[b[i]];//将上面的数的下标对应到下面的数来
		//printf("%d ",b[i]);
	}
	//下面求b的最长递增子序列
	for(i=1;i<=n;i++)
	{
		if(i==1)
		{
			len++;
			dp[len]=b[i];
		}
		else
		{
			if(b[i]>dp[len])//大于就放进去,加后面
			{
				len++;
				dp[len]=b[i];
			}
			else
			{
				j=len;
				while(dp[j]>b[i]&&j>=1)
				{
					j--;
				}
				dp[j+1]=b[i];
			}
		}
	}
	printf("%d",len);
}

下班下班,上选修课都没时间学习了(;´༎ຶД༎ຶ`) 

你可能感兴趣的:(动态规划,算法)