2021年春季学期《算法分析与设计》练习10

问题 A: 最长递增子序列

给出一个序列a1,a2,a3,a4,a5,a6,a7…an,求它的一个子序列(设为s1,s2,…sn),使得这个子序列满足这样的性质:s1<s2<s3<…<sn并且这个子序列的长度最长。输出这个最长子序列的长度,要求时间复杂度为O(n2)。

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
	Scanner cin = new Scanner(System.in);  
    while(cin.hasNext()) {
	 int n=cin.nextInt();
	
	 int a[]=new int[n+1];
	 int b[]=new int[n+1];
	 for(int i=1;i<=n;i++) {
		 a[i]=cin.nextInt();
	 }
	 int result=solve(a,b,n);
	 System.out.println(result);
     
    	
}
    


}
public static  int solve(int []a,int []b,int n){
	b[1]=1;
	int max=b[1];
	int maxlen;
	for(int i=2;i<=n;i++){
		maxlen=0;
		for(int j=i-1;j>=1;j--){
			if(a[j]<a[i]&&b[j]>maxlen){
				maxlen=b[j];
			}
		}
		b[i]=maxlen+1;
		if(b[i]>max){
			max=b[i];
			
		}
		
	}
	return max;
	
	
}

}
	


问题 B: 构造最长递增子序列

在“最长递增子序列”的基础上对代码进行改进,输出一条最长递增子序列。

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
	Scanner cin = new Scanner(System.in);  
    while(cin.hasNext()) {
	 int n=cin.nextInt();
	
	 int a[]=new int[n+1];
	 int b[]=new int[n+1];
	 int c[]=new int[n+1];
	 int pre[]=new int[n+1];
	 for(int i=1;i<=n;i++) {
		 a[i]=cin.nextInt();
	 }
int r=solve(a,b,n,c,pre);
	 for(int i=1;i<=r;i++){
		 System.out.print(c[i]);
		 System.out.print(" ");
		 
	 }
	 
	 System.out.println(); 
    	
}
    


}
public static  int solve(int []a,int []b,int n,int []c,int []pre){
	b[1]=1;
	int max=b[1];
	int maxlen;
	for(int i=2;i<=n;i++){
		maxlen=0;
		for(int j=i-1;j>=1;j--){
			if(a[j]<a[i]&&b[j]>maxlen){
				maxlen=b[j];
				pre[i]=j;
			}
		}
		b[i]=maxlen+1;
		if(b[i]>max){
			max=b[i];
			
		}
		
	}
	maxlen=b[1];
	
	int lab=0;
	for(int i=2;i<=n;i++){
		if(b[i]>maxlen){
			maxlen=b[i];
			lab=i;
		}
	}
	int i=lab;
	int j=maxlen;
	int num=maxlen;
	while(num>0){
		c[j]=a[i];
		j--;
		i=pre[i];
		num--;
	}
	
	return max;
	
}

}
	


问题 C: 0-1背包问题

给定n种物品和一个背包,物品i的重量是Wi,其价值为Vi,背包的容量为C。如何选择装入背包的物品,可以使得装入背包中物品的总价值最大?

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
	Scanner cin = new Scanner(System.in);  
    while(cin.hasNext()) {
	 int n=cin.nextInt();
	  int c=cin.nextInt();
	 int w[]=new int[n+5];
	 int v[]=new int[n+5];
	 int m[][]=new int[n+1][c+1];
	 int x[]=new int[n+5];
	 for(int i=1;i<=n;i++) {
		 v[i]=cin.nextInt();
	 }
	 for(int i=1;i<=n;i++) {
		 w[i]=cin.nextInt();
	 }
	 solve(w,v,c,n,m);
	 traceback(m,w,c,n,x);
	 System.out.println(m[1][c]);
	 for(int i=1;i<=n;i++){
		 System.out.print(x[i]);
	 }
	 System.out.println();
	 
    }
    


}
public static void solve(int w[],int v[],int c,int n,int m[][]){
	int jmax=Math.min(w[n]-1,c);
	for(int j=0;j<=jmax;j++){
		m[n][j]=0;
	}
	for(int j=w[n];j<=c;j++){
		m[n][j]=v[n];
	}
	for(int i=n-1;i>=1;i--){
		jmax=Math.min(w[i]-1,c);
		for(int j=0;j<=jmax;j++){
			m[i][j]=m[i+1][j];
		}
		for(int j=w[i];j<=c;j++){
			m[i][j]=Math.max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
		}
	}
}
public static void traceback(int m[][],int w[],int c,int n,int x[]){
	for(int i=1;i<n;i++){
		if(m[i][c]==m[i+1][c])
			x[i]=0;
		else {
			x[i]=1;
			c=c-w[i];
		}
		
	}
	x[n]=(m[n][c]>0?1:0);
}
}
	


问题 D: X星人的基因

X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?
样例输入 Copy
8
A B C D E A B C
A C C D C B A E
6
A B C D E E
A E D C B B
0

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
    Scanner cin =new Scanner(System.in);
while(cin.hasNext()){
  int n=cin.nextInt();
   if(n==0){
	   break;
   }
   cin.nextLine();//换到下一行因为cin.nextInt()无换行功能
   String str1=cin.nextLine();
   String str2=cin.nextLine();
   str1=str1.replace(" ", "");//将字符串中的空格删去
   str2=str2.replace(" ", "");
   char []a1=str1.toCharArray();//将字符串转成数组
   char []a2=str2.toCharArray(); 
    	
    	
  
  
		 
  
  
    int [][]c=new int[n+5][n+5];
    
    for(int i=0;i<n+5;i++){
    	for(int j=0;j<n+5;j++){
    		c[i][j]=0;
    	}
    }
    double r=lcs(a1,a2,a1.length,a2.length,c);

    double rate=r/n;
   
    if(rate>0.5){
    	System.out.println("No");
    }
    else{
    	System.out.println("Yes");
    }
}
	

}


public static double lcs(char []a1,char []a2,int l1,int l2,int [][]c){
   for(int i=0;i<l1;i++){
	   for(int j=0;j<l2;j++){
		   if(a1[i]==a2[j]){
			   c[i+1][j+1]=c[i][j]+1;
		   }
		   else{
			   if(c[i+1][j]>=c[i][j+1]){
				   c[i+1][j+1]=c[i+1][j];
			   }
			   else{
				   c[i+1][j+1]=c[i][j+1];
			   }
		   }
	   }
   }
   return c[l1][l2];
}

}

这个题目由于我是用Java写的所以输入不太友好,需要一些操作将字符串变成数组。还有就是如果要得到小数被除数与除数一定要有一个是浮点型

问题 E: 出列人数

有N位同学站在一排,体育老师要请其中的(N-K)位同学出列,将剩下的K位同学从左到右依次编号为1,2,3,…K,他们的身高分别为T1,T2,T3,…TK,要求满足T1<T2<T3<…<TK。已知N位同学的身高,请设计一个算法,计算最少需要几位同学出列可使得剩下的同学满足上述要求。

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
	Scanner cin = new Scanner(System.in);  
    while(cin.hasNext()) {
	 int n=cin.nextInt();
	
	 int a[]=new int[n+1];
	 int b[]=new int[n+1];
	 for(int i=1;i<=n;i++) {
		 a[i]=cin.nextInt();
	 }
	 int result=solve(a,b,n);
	 int count=n-result;
	 System.out.println(count);
     
    	
}
    


}
public static  int solve(int []a,int []b,int n){
	b[1]=1;
	int max=b[1];
	int maxlen;
	for(int i=2;i<=n;i++){
		maxlen=0;
		for(int j=i-1;j>=1;j--){
			if(a[j]<a[i]&&b[j]>maxlen){
				maxlen=b[j];
			}
		}
		b[i]=maxlen+1;
		if(b[i]>max){
			max=b[i];
			
		}
		
	}
	return max;
	
	
}

}
	

问题 F: XP的午餐

XP每天都会思考一个问题,今天午餐去哪里吃?这是一个很重要的问题,这会影响到他下午的体力值。他的午餐预算是M元,现在有N种菜品,每一种菜品的价格和能够提供的体力值已知(每种菜品只能选择一次),请问如何选择菜品能够让XP下午的体力值最大呢?

import java.util.Scanner;

public class Main{
	

public static void main(String[] args) {
	Scanner cin = new Scanner(System.in);  
    while(cin.hasNext()) {
    	int c=cin.nextInt();
	 int n=cin.nextInt();
	  
	 int w[]=new int[n+5];
	 int v[]=new int[n+5];
	 int m[][]=new int[n+1][c+1];
	 
	 int j=1,k=1;
	 for(int i=0;i<2*n;i++) {
		 if(i%2==0){
		 w[j]=cin.nextInt();
		 j++;
		 }
		 else{
		 v[k]=cin.nextInt();
		 k=k+1;
		 }
	 }
	
	 solve(w,v,c,n,m);
	 
	 System.out.println(m[1][c]);
	 
	 
    }
    


}
public static void solve(int w[],int v[],int c,int n,int m[][]){
	int jmax=Math.min(w[n]-1,c);
	for(int j=0;j<=jmax;j++){
		m[n][j]=0;
	}
	for(int j=w[n];j<=c;j++){
		m[n][j]=v[n];
	}
	for(int i=n-1;i>=1;i--){
		jmax=Math.min(w[i]-1,c);
		for(int j=0;j<=jmax;j++){
			m[i][j]=m[i+1][j];
		}
		for(int j=w[i];j<=c;j++){
			m[i][j]=Math.max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
		}
	}
}

}
	
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值