关于动规:在这篇博客中,主要讲简单的线性DP.
1.最长上升子序列
题目:输出最长上升的子序列长度
思路:假设f[i]为第i个点的最长上升子序列的个数,那么我们只要找到比它小的最大值然后加上1即可,这是因为如果a[i]是这串序列最前边的数字,所以只要使排在这个数前面的数尽可能地多就好了,这就是这个算法这么做的原因了。
基本代码如下:
for (int i=1;i<=n;i++)
{
int maxx=0;
for (int j=1;j<i;j++)//往前找最大值
if (a[i]>a[j]) maxx=max(maxx,f[j]);//判断符合要求的数并求最大值
f[i]=maxx+1;//求出第i个值的最长子序列
}
程序如下:
#include<bits/stdc++.h>
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;j<i;j++)//往前找最大值
if (a[i]>a[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<<ans;
return 0;
}
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<bits/stdc++.h>
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;j<i;j++)
if (a[i]>a[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<<ans;
return 0;
}
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<bits/stdc++.h>
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<<endl<<f[i];
return 0;
}