【笔试题】百度+美团

发工资

链接:https://www.nowcoder.com/questionTerminal/e47cffeef25d43e3b16c11c9b28ac7e8
来源:牛客网

小度新聘请了一名员工牛牛, 每个月小度需要给牛牛至少发放m元工资(给牛牛发放的工资可以等于m元或者大于m元, 不能低于m)。
小度有一些钞票资金, 一共有n种不同的面额, 对于面额为x_ix
i

的钞票, 小度有y_iy
i

张, 并且每一个钞票面额都能整除所有比它大的面额, 并且每一张钞票不能找零。
小度想知道这部分资金最多能牛牛发放多少个月的工资?

示例1
输入
3 51
100 1
50 4
1 2
输出
4
说明
注意钱不能找零,所以:
100能支付一个月工资
50+1,50+1能支付两个月工资
50+50能支付一个月工资
即最多能支付四个月的工资。

贪心

#include <bits/stdc++.h>
#include <vector>
using namespace std;
struct money{
    long long mon;
    int num;
};
bool cmp(money a, money b){
    return a.mon > b.mon;
}
int main() {
    int a;
    long long sum = 0, b;
    cin >> a >> b;
    money arr[a];
    for(int i = 0; i < a; i++){
        cin>>arr[i].mon>>arr[i].num;
    }
    sort(arr, arr + a, cmp);
    //第一种情况把大于工资的花完,先把大钱用完
    for(int i = 0; i < a; i++){
        if(arr[i].mon >= b){
            sum += arr[i].num;
            arr[i].num = 0;
        }else break;
    }
    //开始车轮战,每一趟while发出一个月工资
    while(true){
        long long needToPay = b;
        //先从大面额开始涮一轮,在不超b的情况下,尽可能地拿大面额
        for(int i = 0; i < a; i++){
            if(arr[i].num == 0) continue;
            //比如需要支付的工资是51,现在的面额是20,那么需要51 / 20 = 2张;并且接下来需要支付的工资变成51 - 40 = 11
            long long needNum = needToPay / arr[i].mon;
            needNum = min(needNum, (long long)arr[i].num);
            arr[i].num -= needNum;
            needToPay -= needNum * arr[i].mon;
        }
        //刚好凑成了就结束这一趟
        if(needToPay <= 0){
            sum++;
            continue;
        }
        //注意是倒序:再从小面额开始补(此时所有面额都已大于needToPay)
        for(int i = a - 1; i >= 0; i--){
            if(arr[i].num == 0) continue;
            arr[i].num--;
            needToPay -= arr[i].mon;
            sum++;
            break;
        }
        if(needToPay > 0) break;
    }
    cout<<sum<<endl;
}
// 64 位输出请用 printf("%lld")

摆火柴

牛牛给了小度n根火柴和m种数字(m只能是1到9),小度只能摆这m种数字,小度想知道能摆出来最大的数的多少。

如图所示: 摆数字1,2,3,4,5,6,7,8,9 分别需要花费 2,5,5,4,5,6,3,7,6根火柴。
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 256M,其他语言512M
输入描述:
第一行两个数n,m。
第二行m个数,表示小度可以摆放的数。
输出描述:
一行表示答案。
示例1
输入例子:
20 4
3 7 8 4
输出例子:
777773
例子说明:
火柴得使用完

贪心+回溯

一种比动规好理解的回溯解法
首先需要字典映射。
当遇到选择列表的时候,可以考虑回溯。
注意先要按照题意排序,按照排序(偏贪心)的基础上,在进行回溯。
最后的结果记得在字母排序

#include<bits/stdc++.h>
using namespace std;

bool backtrack(map<int,int>& mt, vector<pair<int,int>> v, string& ret, int n  ){
    //base case
    if(n==0){
        return true;
    }

    for(int i =0; i< v.size();i++){
        if(v[i].second<=n){//当前得满足剩余的火柴棍得数目
            ret.push_back(v[i].first+'0');
            bool res = backtrack(mt,v,ret,n-v[i].second);//当前字符以及对应得剩余火柴棍数
            if(res) return true;
            ret.pop_back();//回溯
        }
    }

    return false;
}



int main(){

    map<int,int> nums;
    nums[1]=2;
    nums[2]=5;
    nums[3]=5;
    nums[4]=4;
    nums[5]=5;
    nums[6]=6;
    nums[7]=3;
    nums[8]=7;
    nums[9]=6;


    int n,m,x;
    while(cin>>n>>m){
        vector<pair<int,int>> v;
        for(int i =0; i< m;i++){
            cin>>x;
            v.push_back({x,nums[x]});//数字以及对应的火柴棍的数量
        }

        sort(v.begin(),v.end(),[](pair<int,int> a, pair<int,int> b){
            if(a.second!=b.second){
                return a.second< b.second;//火柴棍少的放在前面
            }else{
                return a.first>b.first; //数字大的放前面
            }
        });

        string res="";
        //回溯,来找在满足排序条件下最终能组成得字符串
        backtrack(nums,v,res,n);//当前字符以及对应得剩余火柴棍数
        sort(res.begin(),res.end(),[](char a, char b){
            return a>b;//确保数字从大到小排序,这样得到的就是最大得数字
        });

        cout<<res<<endl;

    }


    return 0;
}

神秘的苹果树

链接:https://www.nowcoder.com/questionTerminal/3f060b099d604ec3875d8826a69a4561
来源:牛客网

小团找到一颗有n个节点的苹果树,以1号节点为根,且每个节点都有一个苹果,苹果都有一个颜色,但是这棵树被施加了咒术,这使得小团只能从某一个节点的子树中选取某一种颜色的拿。小团想要拿到数量最多的那种颜色的所有苹果,请帮帮她。每次她会指定一个节点t,如果小团只能从节点t的子树中选取某一种颜色的苹果,选取什么颜色能拿到最多的苹果?如果有多种颜色都可以拿同样多的苹果,输出颜色编号最小的那个对应的编号。

节点x的子树定义为所有将x当作祖先的节点,x也视为x的子树的一部分。

输入描述:
第一行一个正整数n表示这颗树上节点的个数。

接下来n-1行,每行两个正整数x­­i,yi,表示树上第i条边连接的两个节点。

接下来一行n个正整数c­i,分别表示从1~n号节点上的苹果的颜色。

接下来一行一个正整数q,表示接下来有q次独立的询问。

接下来q行,每行一个正整数t表示询问:如果小团只能从节点t的子树中选取某一种颜色的苹果,选取什么颜色能拿到最多的苹果?如果有多种颜色都可以拿同样多的苹果,输出颜色编号最小的那个对应的编号。

对于100%的数据n≤5000, 1≤xi,yi,t≤n, ci≤1000000000,q≤1000

输出描述:
输出q行,每行一个整数,表示答案。

示例1
输入
7
1 2
1 3
2 4
2 5
3 6
3 7
1 1 2 1 2 2 3
7
1
2
3
4
5
6
7
输出
1
1
2
1
2
2
3

dfs

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, e1, e2;
    cin >> n;
    unordered_set<int> g[n + 1];
    for (int i = 0; i < n - 1; ++i) {
        scanf("%d %d", &e1, &e2);
        g[e1].insert(e2);
        g[e2].insert(e1);
    }

    int color[n + 1];   // 存储每个节点对应的颜色
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &color[i]);
    }


    // 将无向图转化为有向图, 即删除子节点指向父节点的边
    function<void(int, int)> dfs = [&](int u, int p) -> void {
        g[u].erase(p);
        for (int v : g[u]) {
            dfs(v, u);
        }
    };
    dfs(1, -1);

    map<int, int> cnts;  // 记录当前遍历子树的颜色及颜色对应的次数
    function<void(int)> dfs2 = [&](int u) {
        cnts[color[u]]++;
        for (int v : g[u]) {
            dfs2(v);
        }
    };

    int q; cin >> q;
    while (q--) {   // dfs枚举答案
        cnts.clear();
        int node; cin >> node;
        dfs2(node);
        int ma = 0, resColor = -1;
        for (auto [colorIdx, cnt] : cnts) { 
            if (cnt > ma) {
                ma = cnt;
                resColor = colorIdx;
            }
        }
        cout << resColor << endl;
    }
    return 0;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值