20天集训——day12

今天讲dp,这讲的不是一般的快。概念一句话,一道题10分钟带过。我基本上是挂机了一上午。之前老师极其慢的讲时候我都听的一脸懵逼,更不要说这么快的讲课了。今天上午讲了dp,各种背包。c组的越越都不知道01,完全背包怎么用。我懵逼了一上午,到刷题时还要看之前上课的PPT,在慢慢地理解一遍,还有之前集训前老师讲的课和PPT。看着别人的代码再理解一遍时才把题打出来。不会又不敢问老师因为我觉的我啥也不会。所以就、我今天刷的题很少。

第一题:有一种导弹拦截系统,这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。有导弹来袭只有一套系统,因此有可能不能拦截所有的导弹。输入导弹的枚数和导弹依次飞来的高度,计算这套系统最多能拦截多少导弹?如果要拦截所有导弹最少要配备多少套这种导弹拦截系统?这题也就是找最长不上升子序列。用dp写,转移方程是f[i]=max{f[j}+1(1<=j<i);

#include<bits/stdc++.h>
using namespace std;
int main()
{
 int n,l1=0,l2=0;
 int a[210],b[210]={},f[210]={};
 cin>>n;
 for(int i=1;i<=n;i++)
  cin>>a[i];
 f[1]=1;
 for(int i=2;i<=n;i++)
 {
  for(int j=1;j<i;j++)
   if(a[i]<=a[j]&&f[j]>f[i]) f[i]=f[j];
  f[i]++;
 }
 for(int i=1;i<=n;i++)
  if(f[i]>l1)
   l1=f[i];
 b[1]=1;
 for(int i=2;i<=n;i++)
 {
  for(int j=1;j<=i;j++)
   if(a[i]>a[j]&&b[i]<b[j]) b[i]=b[j];
  b[i]++;
 }
 for(int i=1;i<=n;i++)
  if(b[i]>l2)
   l2=b[i];
 cout<<l1<<endl<<l2<<endl;
}

第二题:N位同学站成一排,其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK,则他们的身高满足T1<...Ti+1>…>TK(1<=i<=K)。已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。题目给出的a1<a2<a3<…<ai-1<ai>ai+1>…>an-1>an分解成两份,会得到a1<a2<a3<…<ai-1<ai与ai>ai+1>…>an-1>an.可以将原题转化为先找到一个点i,把原序列分成两组,在得到这两组中必须包括ai的一串正的lis以及一串倒的lis的长度相加在减一.即:ans=max{f1[j]+f2[j]}-1(1<=j<=n).再来看看我们原来的f数组,f[i]代表当前的lis长度,那么就是说我们用O(n^2)的效率算出了所有的lis.将lis正的求一遍得到f1数组,倒的再求一遍得到f2数组.枚举分割点i,找到最大的f1[i]+f2[i]-1,就是剩下的人数m.最少的人走掉意味这最多的人剩下,答案就是n-m.

#include<bits/stdc++.h>
using namespace std;
int main()
{
 int n,maxn=0,l=0;
 int a[110],f1[110]={},f2[110]={};
 cin>>n;
 for(int i=1;i<=n;i++)
  cin>>a[i];
 for(int i=1;i<=n;i++)
 {
  maxn=0;
  for(int j=1;j<i;j++)
   if(a[j]<a[i])
    maxn=max(maxn,f1[j]);
  f1[i]=maxn+1;
 }
 for(int i=n;i>=1;i--)
 {
  maxn=0;
  for(int j=n;j>i;j--)
   if(a[j]<a[i])
    maxn=max(maxn,f2[j]);
  f2[i]=maxn+1;
 }
 maxn=0;
 for(int i=1;i<=n;i++)
  maxn=max(maxn,f1[i]+f2[i]-1);
 l=n-maxn;
 cout<<l;
 return 0;
}

第三题:河两岸总共有N对城市每一对有一条航线来往,开通的航线就互不交叉。兴建哪些航线以使在安全条件下有最多航线可以被开通。 先将一岸的城市排序,再比较到另一岸的路线有没有冲突,和计算。贪心思想,dp。

#include<bits/stdc++.h>
using namespace std;
struct o
{
 int x,y;
}a[5100];
bool cmp(o g,o h)
{
 return g.x<h.x;
}
int main()
{
 int n,m,s,f[5100]={},l=0;
 cin>>n>>m>>s;
 for(int i=1;i<=s;i++)
  cin>>a[i].x>>a[i].y;
 sort(a+1,a+1+s,cmp);
 for(int i=1;i<=s;i++)
 {
  l=0;
  for(int j=1;j<i;j++)
   if(a[j].y<a[i].y)
    l=max(l,f[j]);
  f[i]=l+1;
 }
 l=0;
 for(int i=1;i<=s;i++)
  l=max(l,f[i]);
 cout<<l;
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值