【算法笔记】动态规划 线性DP

关于动规:在这篇博客中,主要讲简单的线性DP.

1.最长上升子序列

题目:输出最长上升的子序列长度
思路:假设f[i]为第i个点的最长上升子序列的个数,那么我们只要找到比它小的最大值然后加上1即可,这是因为如果a[i]是这串序列最前边的数字,所以只要使排在这个数前面的数尽可能地多就好了,这就是这个算法这么做的原因了。

基本代码如下:

for (int i=1;i<=n;i++)
  {
  int maxx=0;
  for (int j=1;ja[j]) maxx=max(maxx,f[j]);//判断符合要求的数并求最大值
  f[i]=maxx+1;//求出第i个值的最长子序列
  }
程序如下:

#include
using namespace std;
int main()
{
	int n,a[10000],f[10000]={};
	cin>>n;
	for (int i=1;i<=n;i++)cin>>a[i];
	for (int i=1;i<=n;i++)
	{
        int maxx=0;
        for (int j=1;ja[j]) 
		  maxx=max(maxx,f[j]);//判断符合要求的数并求最大值
        f[i]=maxx+1;//求出第i个值的最长子序列
    }
    int ans=-1;
    for (int i=1;i<=n;i++)
        if (f[i]>ans) ans=f[i];
    cout<
2.合唱队形

题目:N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高T1<...Ti+1>…>TK(1<=i<=K)。你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

思路:通俗一点,这道题要求的就是求从小到大然后再从大到小的序列的长度(当然最后结果不是这个),假设这个最大点是i,所以i前面的是最长上升子序列,i的右边是最长下降子序列。那么这点想到了,这道题目的解法便一目了然了——我们便可以正反各求一遍最长上升子序列,使最大的某个点的左边右边的最长上升子序列接起来的和-1(减去本身)就是这个序列最长的长度了,最后进行处理一下就可以AC啦!

程序如下:

#include
using namespace std;
int main()
{
	int n,a[10000],f1[10000]={},f2[10000]={};
	cin>>n;
	for (int i=1;i<=n;i++)cin>>a[i];
	for (int i=1;i<=n;i++)
	{
        int maxx=0;
        for (int j=1;ja[j]) 
		  maxx=max(maxx,f1[j]);
        f1[i]=maxx+1;
    }//正
    for (int i=n;i>=1;i--)
	{
        int maxx=0;
        for (int j=n;j>i;j--)
        if (a[i]>a[j]) 
		  maxx=max(maxx,f2[j]);
        f2[i]=maxx+1;
    }//反
    int ans=1111111111;
    for (int i=1;i<=n;i++)
    ans=min(ans,n-(f1[i]+f2[i]-1));//求答案的最小值,即保留序列的最大值
    cout<

3.farmer john收苹果

题意:农场的夏季是收获的好季节。在Farmer John的农场,他们用一种特别的方式来收小苹果:Bessie摇小苹果树,小苹果落下,然后Farmer John尽力接到尽可能多的小苹果。作为一个有经验的农夫,Farmer John将这个过程坐标化。他清楚地知道什么时候(1<=t<=1,000,000)什么位置(用二维坐标表示,-1000<=x,y<=1000)会有小苹果落下。他只有提前到达那个位置,才能接到那个位置掉下的小苹果。一个单位时间,Farmer John能走s(1<=s<=1000)个单位。假设他开始时(t=0)站在(0,0)点,他最多能接到多少个小苹果?Farmer John 在接小苹果时,从某个点到另外一点按照直线来走

思路:这道题和上一道类似,首先在读入的时候应该按时间进行排序,f[i]表示的含义就是在第i个苹果摘的到的前提下找到苹果的最多数,做法和上一道一样(貌似要用到数学方法),最后输出即可。

#include
using namespace std;
struct AC
{
	double x,y;
	int t;
}a[10000]={};
inline bool cmp(AC xx,AC yy)
{
	return xx.t<yy.t;
}
int main()
{
	int n,f[10000]={},ans=-1;
	double v;
	cin>>n>>v;
	for (int i=1;i<=n;i++)
	    cin>>a[i].x>>a[i].y>>a[i].t;
	sort(a+1,a+n+1,cmp);
	for (int i=1;i<=n;i++)
	{
		int maxx=0;
		if (f[i]==0&&sqrt(pow(a[i].x,2)+pow(a[i].y,2))>v*a[i].t) continue;//如何第i个点为第一个点并且无法到达
		for (int j=1;j<i;j++)
		    if (sqrt(pow(abs(a[j].x-a[i].x),2)+pow(abs(a[j].y-a[i].y),2))<=v*(a[i].t-a[j].t)
			    &&f[j]>maxx&&f[j]>0)
		        	maxx=f[j];
		f[i]=maxx+1;
	}
	for (int i=1;i<=n;i++)
	    ans=max(ans,f[i]);
	cout<<ans;
	//for (int i=1;i<=n;i++)cout<
	return 0;
}




 
  



你可能感兴趣的:(【算法笔记】动态规划 线性DP)