8.8 竞技世界 笔试真题

先放代码后放题

第一题 收大白菜

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

int N;
vector<int> val;
// 基于邻接表的有向图
vector<vector<int>> graph;
// 结果数组,能收的最大白菜数量,当前节点,当前收的白菜数量,当前走过的点
void dfs(vector<int>& res, int& iMax, int st, int tem, vector<int>& cur){
    tem += val[st];
    cur.push_back(st);
    //  没有路可走
    if(graph[st].size() == 0){
        if(tem > iMax){
            iMax = tem;
            res = cur;
        } else if(tem == iMax) {
            // 当收的白菜的个数相等时,判断下标的大小,因为数组里面存放的都是下标,直接求和比较即可
            int tot1 = accumulate(res.begin(), res.end(), 0);
            int tot2 = accumulate(cur.begin(), cur.end(), 0);
            if(tot1 > tot2) res = cur;
        }
    }
    // DFS 深搜
    for(int i=0; i<graph[st].size(); i++)
        dfs(res, iMax, graph[st][i], tem, cur);

}
int main(){
    cin >> N;
    // 为了不进行下标的转换,直接多开一维
    val.resize(N+1);
    graph.resize(N+1);
    for(int i=1; i<=N; i++)
        cin >> val[i];
    int tem = 0;
    for(int i=1; i<N; i++)
        for(int j=i+1; j<=N; j++){
            cin >> tem;
            // 如果为 1 代表有一条路,直接存放下标
            if(tem == 1) graph[i].push_back(j);
        }

    vector<int> res;
    vector<int> cur;
    int iMax = 0;
    // dfs 大法好
    dfs(res, iMax, 1, 0, cur);
    cout << iMax << endl;
    for(int i=0; i<res.size()-1; i++)
        cout << res[i] << ' ';
    cout << res.back() << endl;
    return 0;
}

第二题 发工资

大于 50 的部分肯定得优先发 50 100 的,所以先算一下 50 一下的最优解法,后面直接代入即可
想了一下 大于 5 的好像就优先发 大于5的,这块儿还能更加简化一下

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
    int n;
    cin >> n;
    vector<int> val(n, 0);
    for(auto &it:val)
        cin >> it;
    int iMax = *max_element(val.begin(), val.end());
    vector<int> coins{1, 2, 5, 10, 20, 50, 100};
    // 大于 50 的部分肯定是得 50 100 的发
    vector<int> dp(51, 51);
    dp[0] = 0;
    for(int i = 1; i<=min(iMax, 50); i++)
        for(int j=0; j<coins.size() && i >= coins[j]; j++)
            dp[i] = min(dp[i], dp[i-coins[j]] + 1);

    int res = 0;
    for(auto &it:val){
        res += it/100;
        it %= 100;
        res += it/50 + dp[it%50];
    }
    cout << res << endl;
    return 0;
}

优化后的代码,应该能过,不太确定

#include <iostream>
using namespace std;
int main(){
    int n, val, res = 0;
    cin >> n;
    vector<int> coins{100, 50, 20, 10, 5, 2, 1};
    for(int i=0; i<n; i++){
        cin >> val;
        // 每次把当前面额的钱发到发不出为止
        for(auto &i:coins){
            res += val/i;
            val %= i;
        }
    }

    cout << res << endl;
    return 0;
}

第三题 扫雷

吐槽一下,这个备注 1 是不是用来迷惑人的
先写一个方法可以快捷算出周围雷的数量,然后根据逻辑更新一下即可

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int getNum(vector<vector<char>>& grid, int x, int y){
    int res = 0;
    // 两层 for 循环,来算出当前方格周围雷的数量
    for(int i = max(0, x-1); i < min(x+2, (int)grid.size()); i++)
        for(int j = max(0, y-1); j < min(y+2, (int)grid[i].size()); j++){
            if(i == x && j == y) continue;
            if(grid[i][j] == 'M') res++;
        }
    return res;
}
void helper(vector<vector<char>>& grid, int x, int y){
    // 判断边界
    if(x < 0 || y < 0 || x >= grid.size() || y >= grid[x].size()) return;
    // 当前为雷,或者已经走过了,退出
    if(grid[x][y] == 'M' || grid[x][y] != 'E') return ;
    int num = getNum(grid, x, y);
    if(num != 0) {
        // 当前周围有雷,只更新当前点,停止递归
        grid[x][y] = '0' + num;
        return ;
    }
    // 当前周围没有雷,更新当前点,继续递归
    grid[x][y] = 'B';
    helper(grid, x+1, y);
    helper(grid, x-1, y);
    helper(grid, x, y+1);
    helper(grid, x, y-1);
}
int main(){
    vector<vector<char>> grid(4,vector<char>(5));
    for(int i=0; i<4; i++)
        for(int j=0; j<5; j++)
            cin >> grid[i][j];
    int x, y;
    cin >> x >> y;
    // 当前是雷, 直接凉
    if(grid[x][y] == 'M') grid[x][y] = 'X';
    else{
        int num = getNum(grid, x, y);
        // 雷的数量为 0 时,才会进入 DFS
        if(num == 0) helper(grid, x, y);
        else grid[x][y] = '0' + num;
    }
    // 打印输出
    for(auto &it:grid){
        for(auto &i:it)
            cout << i;
        cout << endl;
    }
    return 0;
}

收白菜

图片说明
图片说明

发工资

图片说明
图片说明

扫雷

图片说明
图片说明
图片说明

全部评论

相关推荐

自从我室友在计算机导论课上听说了“刷&nbsp;LeetCode&nbsp;是进入大厂的敲门砖”,整个人就跟走火入魔了一样。他在宿舍门口贴了一张A4纸,上面写着:“正在&nbsp;DP,请勿打扰,否则&nbsp;Time&nbsp;Limit&nbsp;Exceeded。”日记本的扉页被他用黑色水笔加粗描了三遍:“Talk&nbsp;is&nbsp;cheap.&nbsp;Show&nbsp;me&nbsp;the&nbsp;code。”连宿舍聚餐,他都要给我们讲解:“今天的座位安排可以用回溯算法解决,但为了避免栈溢出,我建议用动态规划。来,这是状态转移方程:dp[i][j]&nbsp;代表第&nbsp;i&nbsp;个人坐在第&nbsp;j&nbsp;个位置的最优解。”我让他去楼下取个快递,他不直接去,非要在门口踱步,嘴里念念有词:“这是一个图的遍历问题。从宿舍楼(root)到驿站(target&nbsp;node),我应该用&nbsp;BFS&nbsp;还是&nbsp;DFS?嗯,求最短路径,还是广度优先好。”和同学约好出去开黑,他会提前发消息:“集合点&nbsp;(x,&nbsp;y),我们俩的路径有&nbsp;k&nbsp;个交点,为了最小化时间复杂度,应该在&nbsp;(x/2,&nbsp;y/2)&nbsp;处汇合。”有一次另一个室友低血糖犯了,让他帮忙找颗糖,他居然冷静地分析道:“别急,这是一个查找问题。零食箱是无序数组,暴力查找是&nbsp;O(n)。如果按甜度排序,我就可以用二分查找,时间复杂度降到&nbsp;O(log&nbsp;n)。”他做卫生也要讲究算法效率:“拖地是典型的岛屿问题,要先把连通的污渍区块都清理掉。倒垃圾可以用双指针法,一个指针从左往右,一个从右往左,能最快匹配垃圾分类。”现在我们宿舍的画风已经完全变了,大家不聊游戏和妹子,对话都是这样的:“你&nbsp;Two&nbsp;Sum&nbsp;刷了几遍了?”“别提了,昨天遇到一道&nbsp;Hard&nbsp;题,我连暴力解都想不出来,最后只能看题解。你呢?”“我动态规划还不行,总是找不到最优子结构。今天那道接雨水给我整麻了。”……LeetCode&nbsp;真的害了我室友!!!
老六f:编程嘉豪来了
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务