ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

凤凰院凶真

2021-01-14 22:00:19  阅读:192  来源: 互联网

标签:pre return 5005 int scanf 院凶真 凤凰 dp


文章目录

题目大意

在这里插入图片描述
捆绑数据,害人不浅。
说白了,就是最长公共上升子序列

题解:

初始思想——暴力20%

也不用讲, O ( 2 n ) O(2^n) O(2n)枚举。
来个朴实无华的代码:

#include<bits/stdc++.h> //by 马老师
using namespace std;
int a[10005],b[10005],f[10005];
int n,m;
bool xs(int jg,int djg,int u)
{
	if(djg==jg)
	{
		int t=1;
		for(int i=1;i<=n;i++)
		{
			if(n-i<jg-t)
			{
				return false;
			}
			if(f[t]==a[i])
			{
				t++;
			}
			if(t>jg)
			{
				printf("%d\n",jg);
				for(int j=1;j<=jg;j++)
				{
					printf("%d ",f[j]);
				}
				return true;
			}
		}
	}
	for(int i=u+1;i<=m;i++)
	{
		if(b[i]<=f[djg])
		{
			continue;
		}
		f[++djg]=b[i];
		if(xs(jg,djg,i))
		{
			return true;
		}
		--djg;
	}
	return false;
}
int main()
{
	freopen("okarin.in","r",stdin);
	freopen("okarin.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&b[i]);
	}
	for(int i=m;i>=1;i--)
	{
		if(xs(i,0,0))
		{
			return 0;
		}
	}
	printf("0");
	return 0;
}

初步深入——DP45%

开始看, n n n, m m m都这么小,是不是DP???
怎么设???
d p [ i , j ] dp[i,j] dp[i,j]为取到 α \alpha α世界线和 β \beta β世界线,且取了 β j \beta_j βj​的最长公共上升子序列
考虑转移…(设 α \alpha α为 a a a, β \beta β为 b b b)
如有 k k k,满足 k < j , b k < a i k<j,b_k<a_i k<j,bk​<ai​,我们就能 d p [ i , j ] = d p [ i − 1 ] [ k ] + 1 ( a [ i ] = = b [ j ] ) dp[i,j]=dp[i-1][k]+1(a[i]==b[j]) dp[i,j]=dp[i−1][k]+1(a[i]==b[j])
不用说都明白吧,打代码啊!!!
100就是个优化

深入探索——优化100%

首先考虑如何快速求 k k k…
因为 d p [ i , j ] dp[i,j] dp[i,j]由 d p [ i − 1 ] [ k ] dp[i-1][k] dp[i−1][k]推上来,
所以如果 d p [ i − 1 ] [ k 1 ] dp[i-1][k_1] dp[i−1][k1​]比 d p [ i − 1 ] [ k 2 ] dp[i-1][k_2] dp[i−1][k2​]小,那么 k 1 k_1 k1​是不是废了。
由此,我们可以推出线性,优化成 O ( n m ) O(nm) O(nm)。

	Fu(i,1,n){
		int k=0;
		Fu(j,1,m){
			f[i][j]=f[i-1][j],pre[i][j]=j;
			if(b[j]==a[i]&&f[i-1][k]+1>f[i][j]){
				f[i][j]=f[i-1][k]+1;
				pre[i][j]=k;
			}
			if(b[j]<a[i]&&f[i-1][k]<=f[i][j]) k=j;
		}
	}

Q:如何输出路径

void dfs(int o,int u){
	if(o==0||u==0) return ;
	dfs(o-1,pre[o][u]);
	if(u!=pre[o][u]) printf("%d ",b[u]);
}

参考代码

#include<bits/stdc++.h>
#define rg register
#define Fu(i,a,b) for(rg int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(rg int i=(a);i>=(b);i--)
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
int n,m,f[5005][5005],pre[5005][5005],a[5005],b[5005],u,last;
int c[5005];
void dfs(int o,int u){
	if(o==0||u==0) return ;
	dfs(o-1,pre[o][u]);
	if(u!=pre[o][u]) printf("%d ",b[u]);
}
int main(){
	fre(okarin);
	scanf("%d",&n);
	Fu(i,1,n) scanf("%d",&a[i]);
	scanf("%d",&m);
	Fu(i,1,m) scanf("%d",&b[i]);
	Fu(i,1,n){
		int k=0;
		Fu(j,1,m){
			f[i][j]=f[i-1][j],pre[i][j]=j;
			if(b[j]==a[i]&&f[i-1][k]+1>f[i][j]){
				f[i][j]=f[i-1][k]+1;
				pre[i][j]=k;
			}
			if(b[j]<a[i]&&f[i-1][k]<=f[i][j]) k=j;
		}
	}
	Fu(i,1,m) if(f[n][u]<f[n][i]) u=i;
	printf("%d\n",f[n][u]);
	dfs(n,u);
	Fd(i,c[0],1) printf("%d ",c[i]);
	return 0;
}

标签:pre,return,5005,int,scanf,院凶真,凤凰,dp
来源: https://blog.csdn.net/zhy_Learn/article/details/112639581

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有