动态规划小结

动态规划练习现在也只能说是小节,因为动态规划的内容涉及的范围很广,而且我认为这个算法很难,而且并不是很好理解,他会涉及很多思想,包扩贪心思想,所以总结起来距离熟练掌握并变成自己的东西路还很长。
动态规划看似很难,实则有规律可循,做动态规划题目可将其化为以下四个步骤,需要掌握这种思想,然后做到举一反三。
简单来说动态规划可以分成以下几个步骤
一、确定状态(开一个一维或者二维数组):

(一):寻找最后一步(找到最优策略的最后一步,然后去掉最后一步,分析之前的步骤)

(二):化为子问题(通过不断寻找当前状态的最后一步,并将最后一步去掉分析之前的问题,将规模逐渐变小)

二、确定状态转移方程(根据最后一步和子问题确定)

三、初始条件和边界情况(初始条件是找状态转移方程算不出来的步骤,一般找dp[0],边界条件避免数组越界)

四、计算顺序(大部分一维数组从小到大,二维数组从上到下,从左到右)
动态规划这个算法很常见,也非常重要,那么现在的问题就是给你一个题目,你怎么判断这个题目是不是要用动态规划来求解这个问题
一般可分为三大类问题
第一类就是计数问题,问有多少种方式啊,有多少种方法啊这样的
第二类是求最大值和最小值问题,也是动态规划类题目最常见的考题类型
第三类就是证明是个可行性,存在性的问题,简单来说就是先手或者后手这个我能不能赢这样子,比如常见的取石子问题啊之类的
下面附上几个常见的动态规划题目
最长上升子序列

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 8161 通过数: 4188

【题目描述】
一个数的序列bibi,当b1<b2<…<bSb1<b2<…<bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1,a2,…,aN)(a1,a2,…,aN),我们可以得到一些上升的子序列(ai1,ai2,…,aiK)(ai1,ai2,…,aiK),这里1≤i1<i2<…<iK≤N1≤i1<i2<…<iK≤N。比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。这些子序列中最长的长度是4,比如子序列(1,3,5,8)。

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

【输入】
输入的第一行是序列的长度N(1≤N≤1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

【输出】
最长上升子序列的长度。

【输入样例】
7
1 7 3 5 9 4 8
【输出样例】
4

/这是典型的求最大值最小值问题/

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int n,dp[1005],ma=0,date[1005];
void LIS()
{
	dp[0]=1;
	for(int i=1;i<=n;i++)
	{
		dp[i]=1;
		for(int j=0;j<i;j++)
		{
			if(dp[j]+1>dp[i]&&date[j]<date[i])
			{
				dp[i]=dp[j]+1;
			}
		}
		if(dp[i]>ma)
			ma=dp[i];
	}
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
		cin>>date[i];
	LIS();
	cout<<ma;
	return 0;
}

数字金字塔

时间限制: 1000 ms 内存限制: 65536 KB
提交数: 12145 通过数: 6897

【题目描述】
观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。

在上面的样例中,从13到8到26到15到24的路径产生了最大的和86。

【输入】
第一个行包含R(1≤ R≤1000),表示行的数目。

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

所有的被供应的整数是非负的且不大于100。

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

【输入样例】
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11【输出样例】
86
/这个简单的题目能让你更清楚的明白线性规划的概念,把问题分解成一个树,而重复的树的值可以直接调用/

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int idata=100000+5;
const int idata2=1000+5;
int n,m;
int cnt,flag;
double minn=INT_MAX,maxx=-1;
int aim[idata2][idata2];
int step[idata2][idata2];
int sum;
bool judge;
 
int main()
{
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=i;j++)
        {
            cin>>aim[i][j];
        }
    }
 
    step[1][1]=aim[1][1];
    for(i=2;i<=n;i++)
    {
        for(j=1;j<=i;j++)
        {
            step[i][j]=max(step[i-1][j],step[i-1][j-1])
               +aim[i][j];
        }
    }
 
    for(i=1;i<=n;i++)
        if(maxx<step[n][i])
            maxx=step[n][i];
 
    cout<<maxx<<endl;
    return 0;
}

Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to schedule her next N (1 ≤ N ≤ 1,000,000) hours (conveniently labeled 0…N-1) so that she produces as much milk as possible.

Farmer John has a list of M (1 ≤ M ≤ 1,000) possibly overlapping intervals in which he is available for milking. Each interval i has a starting hour (0 ≤ starting_houri ≤ N), an ending hour (starting_houri < ending_houri ≤ N), and a corresponding efficiency (1 ≤ efficiencyi ≤ 1,000,000) which indicates how many gallons of milk that he can get out of Bessie in that interval. Farmer John starts and stops milking at the beginning of the starting hour and ending hour, respectively. When being milked, Bessie must be milked through an entire interval.

Even Bessie has her limitations, though. After being milked during any interval, she must rest R (1 ≤ R ≤ N) hours before she can start milking again. Given Farmer Johns list of intervals, determine the maximum amount of milk that Bessie can produce in the N hours.

Input

  • Line 1: Three space-separated integers: N, M, and R
  • Lines 2…M+1: Line i+1 describes FJ’s ith milking interval withthree space-separated integers: starting_houri , ending_houri , and efficiencyi

Output

  • Line 1: The maximum number of gallons of milk that Bessie can product in the N hours

Sample Input
12 4 2
1 2 8
10 12 19
3 6 24
7 10 31
Sample Output
43
/这个题要注意的就是要先按结束时间从小到大排一遍,而不是开始时间排序,因为下一次dp的开始是由前一次dp的结束时间再加上间歇的休息时间来完成的/

#include <cstdio>
#include <algorithm>
 #include <iostream>
using namespace std;
const int MAXN=1000+7;
const int inf = 1e9;
int n,m,r;
struct node
{
    int s,e,w;
    bool operator < (const node &a)const
    {
        if(e != a.e)return e < a.e;
        else return s < a.s;
    }
}p[MAXN];
int dp[MAXN];
 
 
int main()
{
    scanf("%d%d%d",&n,&m,&r);
    for(int i = 0 ; i < m ; ++i)
        cin>>p[i].s>>p[i].e>>p[i].w;
    sort(p,p+m);
    for(int i = 0 ; i < m ; ++i)
    {
        dp[i] = p[i].w;
        for(int j = 0 ; j < i ; ++j)
        {
            if(p[i].s - p[j].e >= r)
            {
                dp[i] = max(dp[i],dp[j] + p[i].w);
            }
        }
    }
    int ans = 0 ;
    for(int i = 0 ; i < m ; ++i)ans = max(ans, dp[i]);
    cout<<ans<<endl;
 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值