机考E卷100分题 - 分披萨

题目描述

"吃货"和"馋嘴"两人到披萨店点了一份铁盘(圆形)披萨,并嘱咐店员将披萨按放射状切成大小相同的偶数个小块。但是粗心的服务员将披萨切成了每块大小都完全不同奇数块,且肉眼能分辨出大小。

由于两人都想吃到最多的披萨,他们商量了一个他们认为公平的分法:从"吃货"开始,轮流取披萨。除了第一块披萨可以任意选取外,其他都必须从缺口开始选。

他俩选披萨的思路不同。"馋嘴"每次都会选最大块的披萨,而且"吃货"知道"馋嘴"的想法。

已知披萨小块的数量以及每块的大小,求"吃货"能分得的最大的披萨大小的总和。

输入描述

第 1 行为一个正整数奇数 N,表示披萨小块数量。

  • 3 ≤ N < 500

接下来的第 2 行到第 N + 1 行(共 N 行),每行为一个正整数,表示第 i 块披萨的大小

  • 1 ≤ i ≤ N

披萨小块从某一块开始,按照一个方向次序顺序编号为 1 ~ N

  • 每块披萨的大小范围为 [1, 2147483647]

输出描述

"吃货"能分得到的最大的披萨大小的总和。

用例

输入

5
8
2
10
5
7
123456

输出

19
1

说明:

此例子中,有 5 块披萨。每块大小依次为 8、2、10、5、7。
按照如下顺序拿披萨,可以使"吃货"拿到最多披萨:
“吃货” 拿大小为 10 的披萨
“馋嘴” 拿大小为 5 的披萨
“吃货” 拿大小为 7 的披萨
“馋嘴” 拿大小为 8 的披萨
“吃货” 拿大小为 2 的披萨
至此,披萨瓜分完毕,"吃货"拿到的披萨总大小为 10 + 7 + 2 = 19
可能存在多种拿法,以上只是其中一种。

解题思路

给定一个环形排列的披萨数组,每块披萨有一个美味值,需要计算出从任意位置开始,能够获得的最大美味值总和。

  1. 环形处理:由于披萨是环形排列的,所以在选择披萨时需要考虑边界情况,即当选择了最左边或最右边的披萨后,如何循环到另一端。

  2. 动态规划:使用一个二维数组 dp 作为记忆化存储,其中 dp[L][R] 表示从左边界 L 到右边界 R 能够获得的最大美味值。如果 dp[L][R] 已经被计算过,则直接返回该值。

  3. 递归计算:定义一个递归函数来计算 dp[L][R]。如果 a[L](左边界的披萨美味值)大于 a[R](右边界的披萨美味值),则选择 L 并将 L 向右移动一位;否则选择 R 并将 R 向左移动一位。这样递归地选择下一步,直到只剩下一块披萨。

  4. 递归基:当左右边界相遇时(即 L == R),说明只剩下一块披萨,直接返回这块披萨的美味值作为递归基。

  5. 状态转移:在递归过程中,dp[L][R] 的值是通过比较选择左边界披萨和右边界披萨后,剩下披萨的最大美味值之和来确定的。

C++

#include <iostream>
#include <vector>
#include <algorithm> // 用于 std::max 函数

using namespace std;

int n; // 披萨的数量
vector<int> a; // 每块披萨的美味值
vector<vector<int>> dp; // 记忆化数组,用于存储已计算过的状态

// 计算最大美味值的函数
int allocation(int L, int R) {
    if (dp[L][R] != -1) {
        return dp[L][R]; // 如果已计算过,直接返回结果
    }
    if (a[L] > a[R]) {
        L = (L + 1) % n; // 左边披萨更美味,吃掉左边的
    } else {
        R = (R + n - 1) % n; // 右边披萨更美味,吃掉右边的
    }
    if (L == R) {
        dp[L][R] = a[L]; // 只剩一块披萨时,返回其美味值
    } else {
        // 否则,递归计算剩下披萨的最大美味值,并更新记忆化数组
        dp[L][R] = max(a[L] + allocation((L + 1) % n, R), a[R] + allocation(L, (R + n - 1) % n));
    }
    return dp[L][R]; // 返回当前状态下的最大美味值
}

int main() {
    cin >> n; // 输入披萨的数量
    a.resize(n); // 调整数组大小以存储每块披萨的美味值
    for (int i = 0; i < n; ++i) {
        cin >> a[i]; // 输入每块披萨的美味值
    }
    dp.assign(n, vector<int>(n, -1)); // 初始化记忆化数组

    int ans = 0; // 初始化最大美味值为 0
    for (int i = 0; i < n; ++i) {
        // 更新最大美味值,allocation函数计算从当前披萨开始的最大美味值
        ans = max(ans, allocation((i + 1) % n, (i + n - 1) % n) + a[i]);
    }

    cout << ans << endl;  // 输出最多能吃到的披萨的美味值
    return 0;
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546

Java

import java.util.*;

public class Main {
    static int n;  // 披萨的数量
    static int[] a;  // 每块披萨的美味值
    static int[][] dp;  // 记忆化数组,用于存储已计算过的状态

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();  // 输入披萨的数量
        a = new int[n];  // 初始化存储每块披萨美味值的数组
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextInt();  // 输入每块披萨的美味值
        }
        dp = new int[n][n];  // 初始化记忆化数组,其维度为披萨数量的平方
        for (int[] row : dp) {
            Arrays.fill(row, -1);  // 初始化记忆化数组,将所有值设为-1,表示未计算
        }

        int ans = 0;  // 初始化最大美味值为0
        // 遍历每块披萨,尝试以每块披萨作为起点计算最大美味值
        for (int i = 0; i < n; i++) {
            // 更新最大美味值,allocation函数计算从当前披萨开始的最大美味值
            ans = Math.max(ans, allocation((i + 1) % n, (i + n - 1) % n) + a[i]);
        }

        System.out.println(ans);  // 输出最多能吃到的披萨的美味值总和
    }

    static int allocation(int L, int R) {
        // 如果当前状态已经计算过,则直接返回结果
        if (dp[L][R] != -1) {
            return dp[L][R];
        }
        // 根据贪心策略,选择当前美味值较大的披萨
        if (a[L] > a[R]) {
            L = (L + 1) % n;  // 如果左边的披萨更美味,则吃掉左边的披萨
        } else {
            R = (R + n - 1) % n;  // 如果右边的披萨更美味,则吃掉右边的披萨
        }
        // 如果只剩下一块披萨,则直接返回这块披萨的美味值
        if (L == R) {
            dp[L][R] = a[L];
        } else {
            // 否则,递归计算剩下披萨的最大美味值,并更新记忆化数组
            dp[L][R] = Math.max(a[L] + allocation((L + 1) % n, R), a[R] + allocation(L, (R + n - 1) % n));
        }
        return dp[L][R];  // 返回当前状态下的最大美味值
    }
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950

javaScript

const readline = require('readline');

// 创建 readline 接口
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

let lines = []; // 用于存储输入行的数组
let n; // 披萨的数量
let a; // 每块披萨的美味值
let dp; // 记忆化数组,用于存储已计算过的状态

// 处理输入
rl.on('line', (line) => {
  lines.push(line);
}).on('close', () => {
  // 处理 lines 中的数据
  [n, ...a] = lines.map(Number); // 第一行是披萨的数量,接下来的行是每块披萨的美味值
  a = a.slice(0, n); // 截取前 n 个数字作为美味值数组
  dp = Array.from({ length: n }, () => Array(n).fill(-1)); // 初始化记忆化数组

  let ans = 0; // 初始化最大美味值为 0
  for (let i = 0; i < n; i++) {
    ans = Math.max(ans, allocation((i + 1) % n, (i + n - 1) % n) + a[i]);
  }

  console.log(ans); // 输出最多能吃到的披萨的美味值总和
});

// 计算最大美味值的函数
function allocation(L, R) {
  if (dp[L][R] !== -1) {
    return dp[L][R]; // 如果已计算过,直接返回结果
  }
  if (a[L] > a[R]) {
    L = (L + 1) % n; // 左边披萨更美味,吃掉左边的
  } else {
    R = (R + n - 1) % n; // 右边披萨更美味,吃掉右边的
  }
  if (L == R) {
    dp[L][R] = a[L]; // 只剩一块披萨时,返回其美味值
  } else {
    dp[L][R] = Math.max(a[L] + allocation((L + 1) % n, R), a[R] + allocation(L, (R + n - 1) % n));
  }
  return dp[L][R]; // 返回当前状态下的最大美味值
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

Python

# 用于读取输入的标准库
import sys

# 用于存储输入行的数组
lines = []
# 读取标准输入
for line in sys.stdin:
    lines.append(line.strip())

# 披萨的数量
n = int(lines[0])
# 每块披萨的美味值
a = list(map(int, lines[1:1 + n]))
# 记忆化数组,用于存储已计算过的状态
dp = [[-1 for _ in range(n)] for _ in range(n)]

# 计算最大美味值的函数
def allocation(L, R):
    # 如果已计算过,直接返回结果
    if dp[L][R] != -1:
        return dp[L][R]
    # 根据美味值选择吃掉左边或右边的披萨
    if a[L] > a[R]:
        L = (L + 1) % n
    else:
        R = (R + n - 1) % n
    # 如果只剩一块披萨,返回其美味值
    if L == R:
        dp[L][R] = a[L]
    else:
        dp[L][R] = max(a[L] + allocation((L + 1) % n, R), a[R] + allocation(L, (R + n - 1) % n))
    return dp[L][R]

# 初始化最大美味值为 0
ans = 0
# 计算并更新最大美味值
for i in range(n):
    ans = max(ans, allocation((i + 1) % n, (i + n - 1) % n) + a[i])

# 输出最多能吃到的披萨的美味值总和
print(ans)
1234567891011121314151617181920212223242526272829303132333435363738394041

C语言

#include <stdio.h>
#include <stdlib.h>

int main() {
    int n;  // 披萨的数量
    int *a; // 存储每块披萨美味值的数组
    int **dp; // 记忆化数组,用于存储已计算过的状态

    // 读取披萨的数量
    scanf("%d", &n);
    a = (int *)malloc(n * sizeof(int));

    // 读取每块披萨的美味值
    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    // 初始化记忆化数组
    dp = (int **)malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        dp[i] = (int *)malloc(n * sizeof(int));
        for (int j = 0; j < n; j++) {
            dp[i][j] = -1;
        }
    }

    // 计算最大美味值的函数声明
    int allocation(int, int, int, int *, int **);

    int ans = 0; // 初始化最大美味值为 0
    for (int i = 0; i < n; i++) {
        ans = (ans > allocation((i + 1) % n, (i + n - 1) % n, n, a, dp) + a[i]) ? ans : allocation((i + 1) % n, (i + n - 1) % n, n, a, dp) + a[i];
    }

    // 输出最多能吃到的披萨的美味值总和
    printf("%d\n", ans);

    // 释放分配的内存
    for (int i = 0; i < n; i++) {
        free(dp[i]);
    }
    free(dp);
    free(a);

    return 0;
}

// 计算最大美味值的函数
int allocation(int L, int R, int n, int *a, int **dp) {
    if (dp[L][R] != -1) {
        return dp[L][R]; // 如果已计算过,直接返回结果
    }
    if (a[L] > a[R]) {
        L = (L + 1) % n; // 左边披萨更美味,吃掉左边的
    } else {
        R = (R + n - 1) % n; // 右边披萨更美味,吃掉右边的
    }
    if (L == R) {
        dp[L][R] = a[L]; // 只剩一块披萨时,返回其美味值
    } else {
        dp[L][R] = (a[L] + allocation((L + 1) % n, R, n, a, dp)) > (a[R] + allocation(L, (R + n - 1) % n, n, a, dp)) ? (a[L] + allocation((L + 1) % n, R, n, a, dp)) : (a[R] + allocation(L, (R + n - 1) % n, n, a, dp));
    }
    return dp[L][R]; // 返回当前状态下的最大美味值
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364

完整用例

用例1

3
1
2
3
1234

用例2

5
1
2
3
4
5
123456

用例3

7
10
1
3
5
7
9
2
12345678

用例4

9
8
7
6
5
4
3
2
1
9
12345678910

用例5

5
1
3
5
7
9
123456

用例6

3
5
5
5
1234

用例7

5
21412
100
200
300
400
123456

用例8

5
1
10
2
9
3
123456

用例9

7
2
4
6
8
10
12
14
12345678

用例10

5
2
3
6
7
9
123456
#牛客创作赏金赛#

主要记录自己的刷题日常,学而时习之。

全部评论

相关推荐

首先说明,该文并未对各类群体造成攻击且并未有任何指向意义。暑期实习的时候准备完了,最初的简历现在自己都看不下去,开始投递的时候很多人已经拿到了offer甚至都入职了。后来八月份好不容易找到实习了,刚入职十几家公司突然主动联系我,但是全给拒了。入职后没多久秋招就开始了,当初还心高气傲的觉得能够很快找到一个很好的工作签下三方乖乖实习结束开始学别的。结果马上十月也要结束了,什么东西都没拿到。看到牛客上很多小伙伴已经拿到offer,开始货比三家,自己却一无所有。不知道是自己真的不行还是当初的选择错误。回想自己前几年做的所有选择,高考后准备复读但是精神状态已经没办法支撑我再来一年(抑郁转双相)。进大学后放弃了车辆工程转去大数据,结果两年后电动车突然井喷式发展。在每次放假全部选择回家摆烂,完全没想过实习,到大三下开始不知所措。自己学习了很多东西,却发现市场要求的是实习,即使你会再多没有证明物也是无用的。当初大二感觉后续读研可能会出问题,毅然决然放弃大三复习备考,准备直接工作,却连工作的门槛都够不到。结果今年研究生点扩招一堆,不知道当初的决定是对是错。回顾以往做过的所有选择,也是彻底感悟到了那句永远不要对你没有选择的道理产生幻想。现在开始投实习,为春招做准备吧。又是一次根据当下情况做出的“最好”的选择,只能希望这次有结果吧。无数人告诉我去年到春招才拿到offer,但是春招真的那么简单吗,大厂依旧很难,小厂依旧没有HC,中厂依旧被筛选几百年。上周躯体化发作直接进急诊了,呼吸道痉挛,当时大脑第一次感受到了极致的缺氧。无数人告诉我不要太焦虑,环境不好不是你的问题,但“疫情班”被嘲弄何尝不是对我们这一届的警示呢。即使你不是所谓的“疫情班”但依旧会被歧视。无数人会嘲弄自己为何没早出生几年,尝尝最后的时代红利。时代的一粒沙落在任何人身上都是一座山,孙悟空被压在五指山下500年出来仍是一条好汉,我们被压几十年,真的还能有翻身的机会吗。数据告诉我们我们可能需要37年才能迎来国内高校毕业生骤降,可那是我们早已进入中年,计算机行业届时会怎么样无人知晓。经济规律告诉我们需要几十年才能复苏,可我们真的能等到吗。读书十几年,最后却无从施展自己的能力,有时无力感才是真的压垮骆驼的最后一根稻草。十几年卯足劲往前冲,可到最后自己却连赚钱的门都摸不到。孔乙己的长衫真的是我们不愿脱下吗?从小我们所学习到的东西是读书改变命运,可书我们读了,却比不过别人是头猪在滚滚红利的狂风下也能起飞。脱下长衫向下兼容去做奶茶,这真的是我们想要的吗?如果我没有念大学,我只是一个高中毕业,我可以很自如的接受去做奶茶的现实,但我读了大学,成为了所谓中国前4%的知识分子,却还让我去回归“本行”,试问谁能马上接受。有时真的不是我们自愿去怨天尤人,只是我们为自己不甘,为什么我们出生到现在无数次背负那么多东西,到头来“疫情班”“孔乙己的长衫”“躺平”这些不是我们自己给自己冠以的名词且被一次又一次压在我们身上,我们连反驳的余地都没有。我大抵是病了,已经不知道自己该何去何从,眼前一片雾蒙,无光照进,却仍要低头前行。光亮早已消失,众口却说光在远方,可远方究竟在哪里。
灰太狼4:鼠鼠看完要哭了😭
点赞 评论 收藏
分享
1 2 评论
分享
牛客网
牛客企业服务