最长上升序列模型

二、最长上升序列模型

怪盗基德的滑翔机

![在这里插入图片描述]( https://img-blog.csdnimg.cn/9a4889e4ec9e4b97b25b6552979e77e2.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10

样例输出:

6
6
9

代码模板:

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 100010;
int n;
int a[N],f[N];

int main(){
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		
		//正向求解LIS问题
		int res=0;
		for(int i=1;i<=n;i++)
		{
			f[i]=1;
			for(int j=1;j<i;j++)
				if(a[i]>a[j])
					f[i]=max(f[i],f[j]+1);
			res=max(res,f[i]);
		}
		
		//反向求解LIS问题 
		for(int i=n;i;i--)
		{
			f[i]=1;
			for(int j=n;j>i;j--)
				if(a[i]>a[j])
					f[i]=max(f[i],f[j]+1);
			res=max(f[i],res);
		}
	
		cout<<res<<endl;
	}
}

 

登山

![在这里插入图片描述]( https://img-blog.csdnimg.cn/17ea9459157b4046a23cc4dce219a26a.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

8
186 186 150 200 160 130 197 220

样例输出:

4

代码模板:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1010;
int f[N],g[N]; 
int w[N];
int main() 
{

        int n;
        cin>>n;
        int res =0;
        for(int i=1;i<=n;i++)
        {
            cin>>w[i];
        } 
        for(int i=1;i<=n;i++)
        {
            f[i]=1;
            for(int j=1;j<i;j++)
            {
                if(w[i]>w[j])
                    f[i]=max(f[i],f[j]+1);
            }
        }
        for(int i=n;i>=1;i--)
        {
            g[i]=1;
            for(int j=n;j>i;j--)
            {
                if(w[i]>w[j])
                    g[i]=max(g[i],g[j]+1);
            }
        }
        for(int i=1;i<=n;i++)
            res=max(res,f[i]+g[i]-1);
        cout<<res<<endl;
    return 0;
}

 

友好城市

![在这里插入图片描述]( https://img-blog.csdnimg.cn/89b8dc2a598742a18c669ec3a1a545b8.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
思路:
样例输入:

7
22 4
2 6
10 3
15 12
9 8
17 17
4 2

样例输出:

4

代码模板:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5010;
pair<int, int> a[N];
int n, f[N], res;

int main()
{
    cin >> n;
    for ( int i = 0; i < n; i ++ ) cin >> a[i].first >> a[i].second;
    sort(a, a + n);
    for ( int i = 0; i < n; i ++ )
    {
        f[i] = 1;
        for ( int j = 0; j < i; j ++ )
            if ( a[i].second > a[j].second ) 
                f[i] = max(f[i], f[j] + 1);
        res = max(res, f[i]);
    }
    cout << res;
    return 0;
}

 

导弹拦截

![在这里插入图片描述]( https://img-blog.csdnimg.cn/f221dc8409a84536bec00856f72fbb9c.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

389 207 155 300 299 170 158 65

样例输出:

6
2

样例模板:

#include <sstream>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1010;

int n;
int h[N], f[N], q[N];

int main()
{
    string line;
    getline(cin, line);
    stringstream ssin(line);
    while (ssin >> h[n]) n ++ ;

    int res = 0, cnt = 0;
    for (int i = 0; i < n; i ++ )
    {
        f[i] = 1;
        for (int j = 0; j < i; j ++ )
            if (h[i] <= h[j])
                f[i] = max(f[i], f[j] + 1);
        res = max(res, f[i]);

        int k = 0;
        while (k < cnt && q[k] < h[i]) k ++ ;
        if (k == cnt) q[cnt ++ ] = h[i];
        else q[k] = h[i];
    }

    printf("%d\n", res);
    printf("%d\n", cnt);
    return 0;
}

导弹防御系统

![在这里插入图片描述]( https://img-blog.csdnimg.cn/6d47d34989834c629a133fd6027c6030.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw==,size_20,color_FFFFFF,t_70,g_se,x_16)
样例输入:

5
3 5 2 4 1
0 

样例输出:

2

代码模板:

//暴搜
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 55;

int n;
int q[N];
int up[N], down[N];
int ans;

void dfs(int u, int su, int sd) {
    if (su + sd >= ans) return; // ans不可能再小了

    if (u == n) {
        ans = su + sd;  // su, sd 分别表示 len(up[]), len(down[])
        return;
    }

    // 情况1:将当前数放到上升子序列中
    int k = 0;
    while (k < su && up[k] >= q[u]) k ++;
    int t = up[k];
    up[k] = q[u];
    if (k < su) dfs(u + 1, su, sd);
    else dfs(u + 1, su + 1, sd);
    up[k] = t;

    // 情况2:将当前数放到下降子序列中。
    k = 0;
    while (k < sd && down[k] <= q[u]) k ++;
    t = down[k];
    down[k] = q[u];
    if (k < sd) dfs(u + 1, su, sd);
    else dfs(u + 1, su, sd + 1);
    down[k] = t;
}

int main() {
    while (cin >> n, n) {
        for (int i = 0; i < n; i ++)
            cin >> q[i];

        ans = n;
        dfs(0, 0, 0);

        cout << ans << endl;
    }
}
//迭代加深
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 60;

int n;
int h[N];
int up[N], down[N];

bool dfs(int depth, int u, int su, int sd) {
    // depth 序列上限, su, sd, u 上一个数或者下一个数
    if (su + sd > depth) return false;  // 9 > 8, 深度从0开始
    if (u == n) return true;

    // 枚举所有选法

    // 枚举上升子序列
    bool flag = false;
    for (int i = 1; i <= su; i ++) // 上升子序列
        if (up[i] < h[u]) {
            int t = up[i];
            up[i] = h[u];
            if (dfs(depth, u + 1, su, sd)) return true;
            up[i] = t;
            flag = true;
            break;
        }

    if (!flag) {
        up[su + 1] = h[u];
        if (dfs(depth, u + 1, su + 1, sd)) return true; 
    }

    // 枚举下降子序列
    flag = false;
    for (int i = 1; i <= sd; i ++)
        if (down[i] > h[u]) {
            int t = down[i];
            down[i] = h[u];
            if (dfs(depth, u + 1, su, sd)) return true;
            down[i] = t;
            flag = true;
            break;
        }

    if (!flag) {
        down[sd + 1] = h[u];
        if (dfs(depth, u + 1, su, sd + 1)) return true;
    }

    return false;
}


int main() {

    while (cin >> n, n) {
        for (int i = 0; i < n; i ++) cin >> h[i];

        int depth = 0;
        while (!dfs(depth, 0, 0, 0)) depth ++;

        cout << depth << endl;
    }

    return 0;
}

 

最长公共上升子序列

![在这里插入图片描述]( https://img-blog.csdnimg.cn/ee48df484b7b408bb047b5b9bb11f77a.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw,size_20,color_FFFFFF,t_70,g_se,x_16)
思路:
![在这里插入图片描述]( https://img-blog.csdnimg.cn/867934ee710d4906916fbc5f95f5ff2e.png?x-oss-process=image/watermark ,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAUGFuc2XCtw
,size_20,color_FFFFFF,t_70,g_se,x_16)

样例输入:

4
2 2 1 3
2 1 2 3

样例输入:

2

代码模板:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;

const int N = 3005;
int n,f[N][N],a[N],b[N],st[N];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	
//	for(int i=1;i<=n;i++)
//		for(int j=1;j<=n;j++)
//		{
//			f[i][j]=f[i-1][j];
//			if(a[i]==b[j]){
//			    f[i][j]=max(f[i][j],1);
//				for(int k=1;k<j;k++)
//				{
//					if(b[k]<b[j])
//						f[i][j]=max(f[i][j],f[i][k]+1);
//				}
//			}
//		}

//优化
	for(int i=1;i<=n;i++)
	{
		int maxt=0;
		for(int j=1;j<=n;j++)
		{
			f[i][j]=f[i-1][j];
			if(a[i]==b[j]) f[i][j]=max(f[i][j],maxt+1);
			if(a[i]>b[j]) maxt=max(maxt,f[i-1][j]);
			
		}
	}



	int res=0;
	for(int i=1;i<=n;i++) res=max(res,f[n][i]);
	
	cout<<res<<endl;
	return 0;
}

 

posted @ 2022-03-22 14:15  panse·  阅读(20)  评论(0)    收藏  举报