week10 work签到题+LIS&LCS+拿数问题II

签到题

在这里插入图片描述

思路

  • 对于n每次都有乘以2和乘以3的的选择,利用递归。
  • 当操作的结果等于m的时候,那么意味着能够转换,输出操作次数。
  • 当操作的结果大于m的时候,意味着本次转换失败。
    总结
    在一开始的时候,需要对n和m进行判断,如果n==m,那么转换次数是0。并且如果n>m,那么意味着肯定不能成功转换。

代码

#include<iostream>
using namespace std;
int s=0;
int n = 0, m = 0;
int tag = 0;
void fun(int x,int ts) {
	if (x == m) {
		if(tag==0)cout << ts;
		tag = 1; return;
	}
	else if (x > m)return;
	fun(x * 2, ts + 1);
	fun(x * 3, ts + 1);
}
int main() {
//	while (1)
//	{
		cin >> n >> m;
		s = 0; tag = 0;
		if (n > m) cout << "-1" ;
		else if (m == n) cout << "0";
		else{
			fun(n, s);
			if (tag == 0) cout << "-1";
		}
//	}
	return 0;
}

LIS&LCS

在这里插入图片描述

思路

LIS

  • 对于数组a中的LIS,用f[i]记录以a[i]为结尾的最长上升序列长度,初始时,f数组置0。
  • 当i>1时,对于以ai结尾的最长上升序列,可以分为两部分,ai以前的+ai本身。用j遍历1,2,……i-1,找到所有aj<ai,这些以aj为结尾的最长上升子序列 = 能够放在ai前的所有合乎条件的序列,这些序列的最大长度+1即为以ai为结尾的最长上升子序列的长度。
  • 对于i=1时,f1=1
  • 对于i>1,fi=max{fj | j<i ^ aj<ai }+1

LCS

  • 对于数组a和数组b的LCS,用dp(i,j)记录a1,a2……ai 和 b1,b2……bj的LCS,初始时,dp数组置0。

  • 对于i遍历j,i的范围为数组a的大小,j的范围为数组b的大小

  • 如果ai == bj,那么a1,a2……ai-1和b1,b2……bj-1的LSC长度加上1即为dp(i,j)
    在这里插入图片描述
    上图中dp[i][j]=dp[i-1][j-1]+1

  • 如果ai != bj
    在这里插入图片描述

总结
理解了来用,这种思路挺方便的。先计算出子问题的解,然后再进行选择。

代码

#include<stdio.h>
#define range 5000+10
#include<string.h>
#include<algorithm>
using namespace std;
int a[range],b[range],f[range],dp[range][range];
int n=0,m=0;
int LIS(int arr[],int n){
	memset(f,0,sizeof(f));
	f[1]=1;
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++){
			if(arr[j]<arr[i]){
				f[i]=max(f[i],f[j]);//找最大 
			}
		}
		f[i]++;//加自己 
	}
//	for(int i=1;i<=n;i++) printf("f%d ",f[i]);
	sort(f,f+n+1);
	return f[n];
}
int LCS(int arr1[],int arr2[],int tn,int tm){
	int i=0,j=0;
	for(i=0;i<=tn;i++) 
		for(j=0;j<=tm;j++)
	         dp[i][j]=0;
	for(i=1;i<=tn;i++){
		for(j=1;j<=tm;j++){
			if(arr1[i]==arr2[j])//a的第i个和b的第j个相等
			    dp[i][j]=dp[i-1][j-1]+1;
			else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
	}
//	for(i=0;i<=tn;i++){
//		for(j=0;j<=tm;j++){
//			printf("%d ",dp[i][j]);
//		}
//		printf("\n");
//	}
	return dp[tn][tm];
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=m;i++) scanf("%d",&b[i]);
	printf("%d",LIS(a,n));
	printf(" %d",LCS(a,b,n,m));
	return 0;
} 

拿数问题II

在这里插入图片描述
在这里插入图片描述

思路

  • 上课讲的是对于ai-2,ai-1,ai,ai+1,拿了ai,则ai-1和ai+1就不能拿。dp[i]为考虑a[1],a[2]……a[i]能拿到的最大分数,dp数组里的最大值即为答案。
    初始时,dp数组置0。
    当i=1时,dp[i] = 1;
    当i>=2时,dp[i]如下图;
    在这里插入图片描述
  • 对于本题,只是修改了拿了某个数之后的影响。
  • 对于数i-2,i-1,i,i+1,拿完了i(即没有i),则i-1和i+1就不能拿。
  • 同样使用dp数组,dp[i]为考虑1,2,……i能拿到的最大分数,初始时置为0.
  • 用一个vis数组记录a数组里的数的情况,vis[i]=5,代表有数组a中有5个i。
  • i=1时,dp[1]=i*vis[1]
    i>=2时,如下图

在这里插入图片描述

  • 最终结果为dp数组里的最大值

总结
long long啊!!!,又忘记了/(ㄒoㄒ)/~~

代码

#include<stdio.h>
#include<string.h>
#include<algorithm> 
#define range 100000+10
using namespace std;
long long a[range],vis[range];
long long dp[range];//对数i
int n=0;
long long fun(){
	dp[1]=1*vis[1];
	for(int i=2;i<=range;i++){
		//不拿,dp[i-1]
		//拿,拿vis[i]个,i-2  i-1  i 
		dp[i]=max(dp[i-1],dp[i-2]+i*vis[i]);
	}
	sort(dp,dp+range);
	return dp[range-1];
} 
int main()
{
	scanf("%lld",&n);
	memset(vis,0,sizeof(vis)); 
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		vis[a[i]]++;//个数 
	}
	printf("%lld",fun());
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值