薯队长写了n篇笔记,编号从1~n,每篇笔记都获得了不少点赞数。
薯队长想从中选出一些笔记,作一个精选集合。挑选的时候有两个规则:
1.不能出现连续编号的笔记。
2.总点赞总数最多
如果满足1,2条件有多种方案,挑选笔记总数最少的那种
输入包含两行。第一行整数n表示多少篇笔记。 第二行n个整数分别表示n篇笔记的获得的点赞数。(0<n<=1000, 0<=点赞数<=1000)
输出两个整数x,y。空格分割。x表示总点赞数,y表示挑选的笔记总数。
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]); } } //我这个有什么问题啊,我找不到,通过不了,呜呜呜
#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; }
本题是动态规划问题,设 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; }
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])
#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/
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)
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])
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]); } }
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]); } }
#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; }
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]); } }
这个问题可以通过动态规划来解决。我们定义两个数组dp和count,其中:
动态规划的状态转移方程如下:
初始化:
最终结果为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()))
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]) } }()为啥只通过了八组有没有大佬解读一下
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])