2023/2/10总结

LIS(最长上升子序列)

  1. 最长上升子序列就是一个序列里最长的递增子集并且每个元素可以不连续。

  1. 例如1 7 6 2 3 4的lis就是1 2 3 4,共4个。

  1. 对每个元素来说,最长上升子序列就是他自己本身。

  1. 关键代码:

for(int i=1;i<=n;i++)
    {
        dp[i]=1;//初始化 
        for(int j=1;j
  1. 相关题目:

P1091 [NOIP2004 提高组] 合唱队形

题目描述
n 位同学站成一排,音乐老师要请其中的 �−� nk 位同学出列,使得剩下的 � k 位同学排成合唱队形。
合唱队形是指这样的一种队形:设 � k 位同学从左到右依次编号为 1,2,1,2, … ,�, k,他们的身高分别为 �1,�2, t1, t2, … ,��, tk,则他们的身高满足 �1<⋯<��>��+1> t1<⋯< ti> ti+1> … >��(1≤�≤�)> tk(1≤ ik)。
你的任务是,已知所有 � n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
共二行。
第一行是一个整数 � n(2≤�≤1002≤ n≤100),表示同学的总数。
第二行有 � n 个整数,用空格分隔,第 � i 个整数 �� ti(130≤��≤230130≤ ti≤230)是第 � i 位同学的身高(厘米)。
输出格式
一个整数,最少需要几位同学出列。
输入输出样例
输入 #1复制
8 186 186 150 200 160 130 197 220
输出 #1复制
4
说明/提示
对于 50%50% 的数据,保证有 �≤20 n≤20。
对于全部的数据,保证有 �≤100 n≤100。
  1. 该题可以把他拆分成两个lis来解决,找到一个终点,一边是从左到右递增的lis,一边是从右到左递增的lis。

  1. 需要注意的是在写两个序列的终点是同一个但是计算了两次需要减1。

  1. 求出两边lis的长度后用总数减去再减1就得到答案啦。

  1. 代码如下:

#include"stdio.h"
int a[105],b[105],c[105];
int max(int x,int y)
{
    if(x>y) return x;
    return y;
}
main()
{
    int n,min=9999999;
    int i,j,k;
    scanf("%d",&n); 
    for(i=1;i<=n;i++)
    scanf("%d",&a[i]);
    for(i=1;i<=n;i++)//遍历枚举
    {
        for(j=1;j<=n;j++)//初始化 
        {
            b[j]=1;
            c[j]=1;
        }
        for(j=1;j<=i;j++)// 从左到右求最长上升子序列 
        {
            for(k=1;k<=j;k++)
            {
                if(a[j]>a[k])
                b[j]=max(b[j],b[k]+1);
            }
        }
        for(j=n;j>=i;j--)//从右到左求最长上升子序列 
        {
            for(k=n;k>=j;k--)
            {
                if(a[j]>a[k])
                c[j]=max(c[j],c[k]+1); 
            }     
        }
        if(min>n+1-b[i]-c[i])
        min=n+1-b[i]-c[i];
    }
    printf("%d",min);
}

LCS(最长公共子序列)

  1. 显而易见,lcs就是求两个串相同的lis。

  1. 用二维数组来模拟,代码如下:

#include "stdio.h"
int n,p1[1005],p2[1005];
int i,j;
int dp[1005][1005];
int max(int x,int y)
{ 
    if(x>y) return x;
    return y; 
}
main()
{    
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    scanf("%d",&p1[i]); 
    for(i=1;i<=n;i++)
    scanf("%d",&p2[i]);
    for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
    {
        if(p1[i]==p2[j]) dp[i][j]=dp[i-1][j-1]+1;
        else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
    }
    printf("%d",dp[n][n]);
}
  1. 二分法来解决:

#include"stdio.h"
int a[100005],b[100005],map[100005],dp[100005];
int min(int x,int y)
{
    if(x>y) return y;
    return x;
}
main()
{
    int i,j,n,len=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        map[a[i]]=i;
    }
    for(i=1;i<=n;i++)
    {
        scanf("%d",&b[i]);
        dp[i]=999999;
    }
    dp[0]=0;
    for(i=1;i<=n;i++)
    {
        int l=0,r=len,mid;
        if(map[b[i]]>dp[len]) dp[++len]=map[b[i]];
        else
        {
            while(lmap[b[i]]) r=mid;
                else l=mid+1;
            }
            dp[l]=map[b[i]];
        }
    }
    printf("%d",len);
}

你可能感兴趣的:(算法)