生活依旧在继续
让我们在蓝桥杯的国赛中
都能得到自己满意的答案!
目录
一、开心的金明
解析:
一个基础的01背包问题,每一次购买a价格的物品可以获得b的价值,a为价格,b为价格*重要度
因此,输入的时候:
arr[i][0]=sc.nextInt();
arr[i][1]=arr[i][0]*sc.nextInt();
因为这题数据m<25,所以直接进行循环即可,常规01背包写法
代码:
import java.util.Scanner;
public class 开心的金明 {
static Scanner sc = new Scanner(System.in);
static int n = sc.nextInt();//总金额
static int m = sc.nextInt();//商品类型
static int[][] arr = new int[m][2];
public static void main(String[] args) {
for (int i = 0; i < m; i++) {
arr[i][0] = sc.nextInt();//存放价格
arr[i][1] = sc.nextInt() * arr[i][0];//存放价值
}
int []dp=new int[n+1];
for(int i=0;i<m;i++)
{
for(int j=n;j>=arr[i][0];j--)//注意从m开始
{
dp[j]=Math.max(dp[j],dp[j-arr[i][0]]+arr[i][1]);//dp
}
}
System.out.println(dp[n]);
}
}
二、榨取kkksc03
解析:
这题和上面的开心的金明差不多,不过条件多了一个,那么我们只需要将上面for循环从m开始那边,再增加一个for循环即可
代码:
import java.util.Scanner;
public class 榨取kkksc03 {
static Scanner sc=new Scanner(System.in);
static int n=sc.nextInt();
static int m=sc.nextInt();
static int t=sc.nextInt();
static int [][]arr=new int[1010][1010];
static int [][]brr=new int[1010][2];
public static void main(String[] args) {
for (int i=1;i<=n;i++){
brr[i][0]=sc.nextInt();
brr[i][1]=sc.nextInt();
for (int j=m;j>=brr[i][0];j--)//金币
for (int k=t;k>=brr[i][1];k--){//时间
arr[j][k]=Math.max(arr[j][k],arr[j-brr[i][0]][k-brr[i][1]]+1);
}
}
System.out.println(arr[m][t]);
}
}
三、合唱队形
解析:
首先,我们定任意一个点为最大的点,即T(i-1)<Ti>T(i+1)
那么,因为i不确定,我们就进行一次遍历,依次对每一个值为最大值设置
由此,我们可以得到从1-----n每一个值的最长上升序列
同理,我们再从后往前,计算一个从后往前的最长上升序列
因为每一个位置都存在一个从前往后和从后往前
所以当两个值相加最大时,为最多存下的人数
因此,其余人数为最小出列人数
代码:
import java.util.Scanner;
public class 合唱队形 {
static Scanner sc=new Scanner(System.in);
static int n=sc.nextInt();
static int []arr=new int[n+2];
static int []brr=new int[n+2];
static int []crr=new int[n+2];
public static void main(String[] args) {
for (int i=1;i<=n;i++){
arr[i]=sc.nextInt();
}
for (int i=1;i<=n;i++){//正向的最长上升序列
for (int j=i;j>=0;j--){
if (arr[j]<arr[i])
brr[i]=Math.max(brr[i],brr[j]+1);
}
}
for (int i=n;i>=1;i--){//逆序的最长上升序列(即最长下降序列)
for (int j=i;j<=n+1;j++){
if (arr[i]>arr[j]){
crr[i]=Math.max(crr[i],crr[j]+1);
}
}
}
int max=0;
for (int i=0;i<=n;i++){
max=Math.max(max,brr[i]+crr[i]-1);//减一为当前位置值在往前往后都有计算,计算次数为2
}
System.out.println(n-max);
}
}
四、导弹拦截
解析:
这题只知道
第一问求:最长不上升序列
第二问求:最长上升序列
但是,nlogn的方案没有思路,不会写,但是用上面的方案写可以过n方的部分
具体代码和上面合唱队列差不多
代码:
import java.util.Scanner;
public class 导弹拦截 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
String[] ss = s.split(" ");
int n = ss.length;
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
arr[i] = Integer.parseInt(ss[i]);
}
int max = -1;
int min = -1;
int[] brr = new int[n];
int[] crr = new int[n];
for (int i = 0; i < n; i++) {
brr[i] = 1;
crr[i] = 1;
for (int j = 0; j < i; j++) {
if (arr[j] >= arr[i]) {
brr[i] = Math.max(brr[i],brr[j] + 1);
} else {
crr[i] = Math.max(crr[i], crr[j] + 1);
}
}
max = Math.max(max, brr[i]);
min = Math.max(min, crr[i]);
}
System.out.println(max);
System.out.println(min);
}
}
五、纪念品分组
解析:
这题用的是贪心的思想(运用双指针)
先将整个数组排序,升序降序都可以(我是直接升序排序了)
假设5个值50 60 75 80 90
然后给定的条件是 每组不超过130
那么第一次判断50+90,超过
那么下一次判断50和80,不超过
下一次判断为60和75,超过
下一次60和60,不超过
再下一次判断的是75和50,因为75>50,所以不再判断,结束,输出为4
代码:
import java.util.Arrays;
import java.util.Scanner;
public class 纪念品分组 {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();//每组最大价格
int n=sc.nextInt();//种类
int []arr=new int[n+1];
for (int i=1;i<=n;i++){
arr[i]=sc.nextInt();
}
Arrays.sort(arr,1,n+1);
for (int i=1;i<=n;i++){
System.out.print(arr[i]+" ");
}
int l=1,r=n,sum=0;
while (r>=l) {
if (arr[r] + arr[l] <= m) {
l += 1;
}
sum += 1;
r--;
}
System.out.println(sum);
}
}