得物笔试题目(2023-08-23)

1. 开幕式排练

这道题目想明白了挺简单的,其实就是排序,排序完以后我们希望将相近的数字摆到一起,怎么算相近?两个挨着算相近,但是这样首尾差别是最大的,而题目给出的是最大的身高差,这样操作没有意义。

既然需要处理首尾地方,我们首先排序,奇数位置的数字为一组,偶数位置的数字为一组,将这两组首尾相连,一定是最小的身高差。因为,出了连接处,所有的数字都只差了2个位次,首尾处差了1个位次。

无法找到比这个解更优的排队方案了,因此,它就是正确的。

代码如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> vec(n);
    for (int i = 0; i < n; i++) {
        cin >> vec[i];
    }
    sort(vec.begin(), vec.end());
    int maxVal = 0;
    for (int i = 0; i < n; i++) {
        if (i - 2 >= 0) {
            maxVal = max(maxVal, vec[i] - vec[i - 2]);
        }
    }
    maxVal = max(maxVal, (vec[1] - vec[0]));
    maxVal = max(maxVal, vec[vec.size() - 1] - vec[vec.size() - 2]);
    cout << maxVal;
    return 0;
}

2. 最少数字

背包问题,能过100%:

#include<vector>
#include<iostream>

using namespace std;

int main() {
    int N, M;
    cin >> N >> M;
    vector<int> vec(N);
    for (int i = 0; i < N; i++) {
        cin >> vec[i];
    }
    vector<int> dp(M + 1);
    dp[0] = 0;
    for (int i = 1; i <= M; i++) {
        dp[i] = 0x3f3f3f3f;
    }
    for (int i = 0; i < N; i++) {
        for (int j = M; j >= 0; j--) {
            if (j - vec[i] >= 0)
                dp[j] = min(dp[j], dp[j - vec[i]] + 1);
        }
        if(dp[M] == 1) break;
    }
    if (dp[M] == 0x3f3f3f3f)
        cout << "No solution";
    else
        cout << dp[M];
    return 0;
}

最开始没看出来,采用dfs,只能过45%:

#include<iostream>
#include<vector>
using namespace std;
void dfs(int& minNum, int curNum, int curSum, int M, vector<int>& vec, int index) {
    if (curSum == M) {
        if (curNum < minNum) {
            minNum = curNum;
        }
        return;
    }
    if (curSum > M) { // 后边不可能存在解了
        return;
    }
    if (index >= vec.size())return;
    // 要 index 位的数字
    dfs(minNum, curNum + 1, curSum + vec[index], M, vec, index + 1);
    // 不要 index 的数字
    dfs(minNum, curNum, curSum, M, vec, index + 1);
    return;
}
int main() {
    int N, M;
    cin >> N >> M;
    vector<int> vec(N);
    for (int i = 0; i < N; i++) {
        cin >> vec[i];
    }
    int minVal = 0x3f3f3f3f;
    dfs(minVal, 0, 0, M, vec, 0);
    cout << minVal;
    return 0;
}

排序优化了下,能过63%:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

int dfs(int curNum, int curSum, int M, vector<int>& vec, int index) {
    if (curSum == M) {
        return curNum;
    }
    if (curSum > M) { // 后边不可能存在解了
        return -1;
    }
    if (index >= vec.size())return -1;
    int res;
    // 要 index 位的数字
    res = dfs(curNum + 1, curSum + vec[index], M, vec, index + 1);
    if (res != -1) {
        return res;
    }
    // 不要 index 的数字
    res = dfs(curNum, curSum, M, vec, index + 1);
    if (res != -1) {
        return res;
    }
    return -1;
}
int main() {
    int N, M;
    cin >> N >> M;
    vector<int> vec(N);
    for (int i = 0; i < N; i++) {
        cin >> vec[i];
    }
    sort(vec.begin(), vec.end(), greater<int>());
    // int minVal = 0x3f3f3f3f;
    int minVal = dfs(0, 0, M, vec, 0);
    if (minVal == -1)
        cout << "No solution";
    else
        cout << minVal;
    return 0;
}

全部评论
第一题的题目不能细看,细看都不知道在讲啥,凭着一种朦胧的感觉才能ac
2 回复 分享
发布于 2023-08-24 11:36 澳大利亚
清华✌🏻
点赞 回复 分享
发布于 2023-08-24 01:04 四川
我刚开始也想用dp,但是看了n和m的范围,觉得O(m*n)的肯定超时。结果还真是这么做
点赞 回复 分享
发布于 2023-08-24 01:07 陕西
第二题写中间遍历循序写反了,后改成dfs,血亏
点赞 回复 分享
发布于 2023-08-24 01:13 辽宁
我怎么记得第二题每个重复数字最多用一次,然后就一直卡64
点赞 回复 分享
发布于 2023-08-24 07:05 上海
清华✌牛逼,我昨晚也做了,两道都是36%
点赞 回复 分享
发布于 2023-08-24 10:15 江苏
点赞 回复 分享
发布于 2023-08-24 10:51 山西
开幕式根据用例的提示,最大方中间两遍递减的思路
点赞 回复 分享
发布于 2023-08-25 13:29 上海

相关推荐

点赞 评论 收藏
分享
评论
8
34
分享
牛客网
牛客企业服务