首页 > 试题广场 >

笔记精选

[编程题]笔记精选
  • 热度指数:5480 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
 薯队长写了n篇笔记,编号从1~n,每篇笔记都获得了不少点赞数。    
薯队长想从中选出一些笔记,作一个精选集合。挑选的时候有两个规则:
 1.不能出现连续编号的笔记。 
2.总点赞总数最多 
如果满足1,2条件有多种方案,挑选笔记总数最少的那种

输入描述:
输入包含两行。第一行整数n表示多少篇笔记。 第二行n个整数分别表示n篇笔记的获得的点赞数。   
 (0<n<=1000,    0<=点赞数<=1000) 


输出描述:
输出两个整数x,y。空格分割。
 x表示总点赞数,y表示挑选的笔记总数。
示例1

输入

4
1 2 3 1

输出

4 2
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] f=new int[n+1];//总点赞数
        int[] count=new int[n+1];//挑选笔记数
        int[] up=new int[n+1];//每一篇的点赞数
       
        for(int i=1;i<=n;i++){
            up[i]=sc.nextInt();
        }
        count[1]=1;
        f[1]=up[1];
        for(int i=2;i<=n;i++){
            f[n]=Math.max(f[n-2]+up[n],f[n-1]);
            if(f[n]==f[n-1]){
                count[n]=count[n-1];
            }else{
                count[n]=count[n-2]+1;
            }
             }
        System.out.println( f[n]+" "+count[n]);
    }
}
//我这个有什么问题啊,我找不到,通过不了,呜呜呜

发表于 2020-08-28 09:47:36 回复(0)
#include <iostream>
#include <vector>

using namespace std;
int buffer[10001];

int main()
{
    int n;
    cin >> n;
    for(int i=0; i<n; ++i) cin >> buffer[i];
    
    vector<pair<int, int>> dp(n);
    for(int i=0; i<n; ++i){
        if(i == 0) dp[i].first = buffer[i], dp[i].second = 1;
        else{
            auto cur = buffer[i] + (i-2 >= 0 ? dp[i-2].first : 0);
            auto cnt = i-2 >= 0? dp[i-2].second +1 : 1;
            
            if(cur > dp[i-1].first) dp[i] = {cur, cnt};
            else dp[i] = dp[i-1];
        }
    }
    cout << dp.back().first << ' ' << dp.back().second;
    return 0;
}

发表于 2020-06-14 11:42:32 回复(1)

本题是动态规划问题,设 dp[i] 为前 i 个物品的最大挑选赞数, 状态转移方程是dp[i]=max(dp[i-1], dp[i-2]+nums[i])

#include<bits/stdc++.h>

using namespace std;

#define MAX_N 1010
int N;
int nums[MAX_N];

int main() {
    scanf("%d", &N);
    for (int i = 0; i < N; ++i) {
        scanf("%d", &nums[i]);
    }

    int dp_0 = 0;
    int dp_1 = 0;
    int num_0 = 0, num_1 = 0;
    for (int i = 0; i < N; ++i) {
        int temp = dp_1;
        int num_temp = num_1;
        if (dp_1 < dp_0+nums[i]) {
            dp_1 = dp_0+nums[i];
            num_1 = num_0+1;
        }
        dp_0 = temp;
        num_0 = num_temp;
    }

    printf("%d %d\n", dp_1, num_1);
    return 0;
}
发表于 2020-06-11 19:32:52 回复(0)
n =int(input())
notes =list(map(int,input().split(" ")))
 
ifn ==0:
    print(0,1)
    exit()
ifn<=2:
    print(max(notes),1)
    exit()
dp =[0fori inrange(n)]
nums =[1fori inrange(n)]
 
dp[0] =notes[0]
dp[1] =notes[1]
dp[2] =notes[2] +dp[0]
nums[2] =2
 
fori inrange(3,n):
    ifdp[i-2] >dp[i-3]:
        dp[i] =dp[i-2]+notes[i]
        nums[i] +=nums[i-2]
        continue
    ifdp[i-3]>dp[i-2]:
        dp[i] =dp[i-3]+notes[i]
        nums[i] +=nums[i-3]
        continue
    ifnums[i-3]<nums[i-2]:
        dp[i] =dp[i-3]+notes[i]
        nums[i] +=nums[i-3]
        continue
    nums[i] +=nums[i-2]
    dp[i] =dp[i-2] +notes[i]
r =-1
ind =-1
#print (notes)
#print (dp)
fori inrange(len(dp)):
    ifdp[i]>r:
        r =dp[i]
        ind =i
print(r,nums[ind])
#不知道为啥只有90%,请大佬帮我康康
发表于 2020-06-02 20:24:27 回复(2)
✭头像
类似打家劫舍的问题。利用动态规划
dp[i] = x 表示从i开始选笔记,最大点赞数为x。dpNum[i]表示此时选取的次数
动态转移方程为dp[i] = max(dp[i+1], dp[i+2]+nums[i])
由于本题还需要求次数,所以再构造一个dpNum数组,用来存储得到dp[i]时,选取的笔记次数。状态方程与dp数组类似,当选取了nums[i],则dpNum[i] = dpNum[i+2]+1,否则在不选取的情况下,dpNum[i]=dpNum[i+1]
从后往前迭代求解,所以数组需初始化大小为n+2,初值均为0(方便求解dp[n-1])
import sys
n = eval(input())
nums = [int(i) for i in sys.stdin.readline().split()]
dp = [0 for _ in range(n+2)]
dpNum = [0 for _ in range(n+2)]
num = 0
for i in range(n-1, -1, -1):
    if dp[i+1] < dp[i+2]+nums[i]:
        dp[i] = dp[i+2]+nums[i]
        dpNum[i] = dpNum[i+2]+1
    else:
        dp[i] = dp[i+1]
        dpNum[i] = dpNum[i+1]
print(dp[0], dpNum[0])
编辑于 2020-06-26 11:49:10 回复(0)
思路:要在一个连续的数组里面选k个数,使得这k个数的点赞最多,并且还不能选编号连续的数(比如选了nums[i],就不能选nums[i + 1],只能选nums[i + 2]........),那也就是说:要得到最大的点赞量,要看你前面是怎么选的,那既然后面的结果受前面的选择所影响,很容易联想到动态规划,因为通俗地讲,动态规划就是一个递推式,由前面推到后面,我们需要推到第n个数,从第1个数开始推。这样,我们定义dp(n + 1),dp[i]就表示选到第i个数的时候,能获得的最大点赞数。最终的dp[n]就该是需要输出的最大点赞数。
那接下来就是怎么推的问题了。首先,遇到一个数nums[i],我有两种选择:选这个数,那么意味着我前面的nums[i - 1]不能选,只能选nums[i - 2];不选这个数呢?那么意味着我可以选nums[i - 1],由于我要取最大点赞数,所以取它们俩的大者 赋值到dp[i]即可,以此类推到n。
至此,基本思路讲解完毕,现在还有一个问题,我们需要统计选了几个数。这个比较简单,选一个就+1,嘛,所以count[i] = count[i - 2] + 1; 或者 count[i] = count[i - 1],这时候应该可以理解这两句话的含义了吧,就是选与不选nums[i]的问题了。下面看代码:
#include <iostream>
#include <vector>
using namespace std;

// dp[i]: 从第一篇笔记开始选到第i篇, 所能得到的最大点赞数。
// count[i]: 此时选取的笔记数量
int main(){
    int n, val;
    cin >> n;
    vector<int> vec(n + 1, 0);
    for(int i = 1; i <= n; ++i){
        cin >> val;
        vec[i] = val;
    }
    vector<int> dp(n + 1, 0);  
    vector<int> count(n + 1, 0);
    dp[1] = vec[1];  //选第一篇笔记, 最大点赞数自然就是vec[1]
    count[1] = 1;    //选了一个数
    for(int i = 2; i <= n; ++i){
        //选了dp[i - 2], 就不能选dp[i - 1], 但可以选vec[i](不能连续)
        if(dp[i - 1] < dp[i - 2] + vec[i]){
            dp[i] = dp[i - 2] + vec[i];
            count[i] = count[i - 2] + 1;
        } else{
            //不选dp[i - 2]和vec[i]
            dp[i] = dp[i - 1];
            count[i] = count[i - 1];
        }
    }
    cout << dp[n] << ' ' << count[n] << endl;
    return 0;
}
最后,leetcode 337题 打家劫舍III,思路类似,只不过从数组变成二叉树,感兴趣的可以试试。https://leetcode-cn.com/problems/house-robber-iii/

编辑于 2020-11-29 13:02:46 回复(1)
参考了大佬们的解法。
def getMaxStar(n,nums):
    dp = [0 for _ in range(n+1)]
    dp2 = [0 for _ in range(n+1)]
    dp[1] = nums[0]
    dp2[1] = 1
    for i in range(2,n+1):
        if dp[i-1] < dp[i-2]+nums[i-1]:
            dp[i] = dp[i-2]+nums[i-1]
            dp2[i] = dp2[i-2]+1
        else:
            dp[i] = dp[i-1]
            dp2[i] = dp2[i-1]
    print(dp[-1], dp2[-1])
    
n = eval(input())
nums = [int(i) for i in input().split()]
getMaxStar(n, nums)
	


编辑于 2020-07-21 18:22:00 回复(0)
虽然很别扭 代码也不是很简洁 直接复制到 牛客网这个JavaScript V8 里面 还是能通过的
var a = readline();
var c = readline();
c = c.split(" ");
    var b = c.map(item =>{
      return Number(item)
    })
var point = [];
var num = [];
point[0] = b[0];
num[0] = 1;
point[1] = Math.max(b[0],b[1]);
num[1] = 1;
for (var i = 2; i < b.length; i++) {
   if(b[i] + point[i - 2] > point[i - 1]){
       point[i] = b[i] + point[i - 2];
       num[i] = 1 + num[i-2];
    } else {
       point[i] = point[i - 1];
       num[i] = Math.min(num[i - 1] , 1 + num[i - 2])
    }
}
var res = [];
res.push(Math.max(...point));
let record = point.indexOf(res[0]);
res.push(num[record])
console.log(res[0] , res[1]) 


发表于 2020-07-08 15:46:31 回复(1)
***头像 ***
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=Integer.parseInt(sc.nextLine());
        int[] num=new int[n];
        for(int i=0;i<n;i++){
            num[i]=sc.nextInt();
        }
        int[] dp=new int[n+1];
        if(num.length==1){
            System.out.println(num[0]+" "+1);
        }
        if(num.length==2){
            System.out.println((num[0]>num[1]?num[0]:num[1])+" "+1);
        }
        
        dp[0]=num[0];
        dp[1]=num[0]>num[1]?num[0]:num[1];
        int[] dpN=new int[n];
        dpN[0]=1;
        dpN[1]=1;
        for(int i=2;i<n;i++){
            if(dp[i-1]<dp[i-2]+num[i]){
                dp[i]=dp[i-2]+num[i];
                dpN[i]=dpN[i-2]+1;
            }else{
                dp[i]=dp[i-1];
                dpN[i]=dpN[i-1];
            }
        }
        System.out.println(dp[n-1]+" "+dpN[n-1]);
        
    }
    
    
    
}

发表于 2022-03-12 23:21:44 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] counts = new int[n];
        for(int i = 0; i < n; i++){
            counts[i] = in.nextInt();
        }
        //从右向左看,第i个开始的点赞数 
        //选取n+1作为容量且从1开始的原因是判断时需要n-2选项。dp[0]=0
        int[] dp = new int[n+1];
        dp[1] = counts[0];
        int[] cp = new int[n+1]; 
        //不赋值,初始值默认为0,不符合实际。
        cp[1] =1;
        for(int i=2;i<n+1;i++){
            //选取自己作为第一个与选取后一个比那一个更大
            if(dp[i-2]+counts[i-1]>dp[i-1]){
                dp[i] = dp[i-2]+counts[i-1];
                cp[i] = cp[i-2]+1;
            }else{
                dp[i] = dp[i-1];
                cp[i] = cp[i-1];
            }
        }
        System.out.println(dp[n]+" "+cp[n]);
    }
}

编辑于 2021-10-08 20:25:44 回复(5)
求方案的做法,借鉴评论区。
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n;
    while(cin>>n)
    {
        vector<int> v(n+1);
        int num=0;
        for(int i=1;i<=n;i++)
        {
            cin>>num;
            v[i]=num;
        }
        int dp[n+1];
        int dpNum[n+1];
        memset(dpNum,0,sizeof dpNum);
        memset(dp,0,sizeof dp);
        dp[1]=v[1];dpNum[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(dp[i-2]+v[i]>dp[i-1])
            {
                dp[i]=dp[i-2]+v[i];
                dpNum[i]=dpNum[i-2]+1;
            }
            else{
                dp[i]=dp[i-1];
                dpNum[i]=dpNum[i-1];
            }
        }      
        cout<<dp[n]<<" "<<dpNum[n]<<endl;
    }
    return 0;
}


发表于 2020-09-05 16:17:06 回复(0)
打家劫舍,动态规划,选与不选的最优问题
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] nums = new int[n];
        for(int i = 0; i < nums.length; i++) {
            nums[i] = sc.nextInt();
        }
        int[] dp = new int[n+1]; // 总点赞数
        dp[1] = nums[0];
        int[] dpN = new int[n+1]; // 挑选笔记数
        dpN[1] = 1;
        for(int i = 2; i <= n; i++) {
            if(dp[i-1] < dp[i-2] + nums[i-1]) { // 选
                dp[i] = dp[i-2] + nums[i-1];
                dpN[i] = dpN[i-2] + 1;
            } else { // 不选
                dp[i] = dp[i-1];
                dpN[i] = dpN[i-1];                
            }
        }
        System.out.println(dp[n] + " " + dpN[n]);
    }
}

发表于 2020-08-30 19:34:30 回复(1)
#include<vector>
#include<iostream>
using namespace std;

//dp[i],i时候,最多点赞数。dpnum[i],i时候,篇数。
int main() {
    int n;
    cin >> n;
    vector<int> v;
    for (int i = 0; i < n; i++) {
        int tp;
        cin >> tp;
        v.push_back(tp);
    }
    vector<int> dp(n), dpnum(n);
    dp[0] = v[0];
    dp[1] = (v[0] > v[1]) ? v[0] : v[1];
    dpnum[0] = 1;
    dpnum[1] = 1;
    for (int i = 2; i < n; i++) {
        //选用了v[i],所以篇数+1
        if ((v[i] + dp[i - 2]) > dp[i - 1]) {
            dp[i] = v[i] + dp[i - 2];
            dpnum[i] = 1+ dpnum[i - 2];
        }
        //没有选用,所以篇数为前一个,即dpnum[i - 1]
        else
        {
            dp[i] = dp[i - 1];
            dpnum[i] = dpnum[i - 1];
        }
    }

    cout << dp[n-1]<<' '<< dpnum[n - 1];

}
发表于 2020-08-22 21:28:19 回复(0)
total = int(input())
data = [int(i) for i in input().split()]
dp = [0 for _ in range(total)]
dp_count = [1 for _ in range(total)]
dp[0= data[0]
dp[1= max(data[0], data[1])
for n in range(2, total):
    dp[n] = max(dp[n-1], dp[n-2]+data[n])
    if dp[n-1< dp[n-2]+data[n]:
        dp_count[n] = dp_count[n-2]+1
    else:
        dp_count[n] = dp_count[n-1]
print(dp[total-1], dp_count[total-1])
发表于 2020-07-03 22:58:34 回复(0)

这个问题可以通过动态规划来解决。我们定义两个数组dp和count,其中:

  • dp[i]表示在前i篇笔记中能获得的最多点赞数。
  • count[i]表示在前i篇笔记中能获得dp[i]个点赞数所需要的最少笔记数。

动态规划的状态转移方程如下:

  • 如果不选第i篇笔记,则有dp[i] = dp[i-1],并且count[i] = count[i-1]。
  • 如果选第i篇笔记,则有dp[i] = dp[i-2] + likes[i](第i篇笔记的点赞数),并且count[i] = count[i-2] + 1。

初始化:

  • dp[0] = likes[0],count[0] = 1
  • dp[1] = max(likes[0], likes[1]),count[1] = 1 if likes[0] < likes[1] else 1

最终结果为dp[n-1]和count[n-1]。

def select_notes(n, likes):
    if n == 0:
        return 0, 0
    if n == 1:
        return likes[0], 1

    # 初始化dp和count数组
    dp = [0] * n  # 在前 i 篇笔记中能获得的最多点赞数
    count = [0] * n  # 在前 i 篇笔记中能获得 dp[i] 个点赞数所需要的最少笔记数

    dp[0] = likes[0]
    count[0] = 1

    dp[1] = max(likes[0], likes[1])
    count[1] = 1  # 不能选连续的,只能二选一,选大的

    for i in range(2, n):
        if dp[i - 1] >= dp[i - 2] + likes[i]:  # 只是>不行,无法使笔记数最小
            dp[i] = dp[i - 1]
            count[i] = count[i - 1]
        else:
            dp[i] = dp[i - 2] + likes[i]
            count[i] = count[i - 2] + 1

    return dp[-1], count[-1]


# 输入处理
n = int(input())
likes = list(map(int, input().split()))


发表于 2024-07-02 21:59:37 回复(0)
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void async function () {
    // Write your code here
    while(line = await readline()){
        let arr=line.split(' ')
        let dp=[]
        let g=[]
       
        if(arr.length<2) continue
        arr=arr.map((item)=>{
            return Number(item)
        })
        dp[0]=arr[0]
        dp[1]=arr[1]
        g[0]=1
        g[1]=1
        for(let i=2;i<arr.length;i++){
           dp[i]=Math.max(dp[i-1],dp[i-2]+arr[i])
           if(dp[i]==dp[i-2]+arr[i]){
              g[i]=g[i-2]+1
           }else{
              g[i]=g[i-1]
           }
        }
        console.log(dp[arr.length-1]+" "+g[arr.length-1])
    }
}()
为啥只通过了八组有没有大佬解读一下
发表于 2023-09-19 14:10:28 回复(0)
动态规划+贪心
n = int(input())
line = [int(i) for i in input().split()]

if n == 0:
    print(0, 0)
elif n == 1:
    print(line[0], 1)
else:
    # dp[i] 表示考虑到第 i 篇笔记时的最大点赞总数
    dp = [0] * n
    # count[i] 表示达到 dp[i] 的点赞总数时所选笔记的最少数量
    count = [0] * n
    
    dp[0] = line[0]
    count[0] = 1
    dp[1] = max(line[0], line[1])
    count[1] = 1 if line[0] > line[1] else 1
    
    for i in range(2, n):
        if dp[i-2] + line[i] > dp[i-1]:
            dp[i] = dp[i-2] + line[i]
            count[i] = count[i-2] + 1
        elif dp[i-2] + line[i] == dp[i-1]:
            dp[i] = dp[i-2] + line[i]
            count[i] = min(count[i-2] + 1, count[i-1])
        else:
            dp[i] = dp[i-1]
            count[i] = count[i-1]

    print(dp[-1], count[-1])


发表于 2024-08-06 12:03:26 回复(0)
看结果好像是对的
function dpNote(num: number, nums: number[]) {
if (nums.length === 0) return 0
if (nums.length === 1) return nums[0]

const dp = new Array(num).fill(0)//点赞数
const dpNum = new Array(num).fill(0)//笔记数

dp[0] = nums[0]
dpNum[0] = 1
dp[1] = Math.max(nums[0], nums[1])
dpNum[1] = 1

for (let i = 2; i < nums.length; i++) {
if (dp[i - 1] < dp[i - 2] + nums[i]) {
dpNum[i] = dpNum[i - 1]
}else{
dpNum[i] = dpNum[i - 1] + 1
}
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i])
}
console.log(dp[nums.length - 1])//点赞数
console.log(dpNum[nums.length - 1])//笔记数
}
发表于 2024-02-23 17:39:49 回复(0)
字符串变为数组以后,可以使用数组的reverse进行翻转,然后在spilt将数组转为字符串
编辑于 2024-01-18 15:34:43 回复(0)
参考力扣打家劫舍,不仅要计算出抢得的财物数量,还需要计算抢的房间数量最小
n = int(input())
li = input().split()
li = [int(l) for l in li]

if n == 0:
    print(0, 0)
elif n == 1:
    print(li[0], 1)
else:
    dp = [0 for _ in range(n)]
    dp[0] = li[0]
    dp[1] = max(li[:2])
    num = [0 for _ in range(n)]
    num[0] = 1
    num[1] = 1
    for i in range(2, n):
        if dp[i-1] < (dp[i-2] + li[i]):
            dp[i] = dp[i-2] + li[i]
            num[i] = num[i-2] + 1
        else:
            dp[i] = dp[i-1]
            num[i] = num[i-1]
    print(dp[-1], num[-1])
发表于 2023-07-18 10:58:12 回复(0)