腾讯2018安卓实习正式笔试题

我是真的菜。


第一题——画家小Q

题意

画家小Q又开始他的艺术创作。小Q拿出了一块有N×M像素格的画板,画板初始状态是空白的,用“X”表示。
小Q有他独特的绘画技巧,每次小Q会选择一条斜线:
如果斜线的方向形如‘/’即斜率为1,小Q会选择这条斜线中的一段格子,都涂画为蓝色,用‘B’表示;
如果对角线的方向形如‘\’,即斜率为-1,小Q会选择这条斜线中的一段格子,都涂画为黄色,用‘Y’表示。
如果一个格子既被蓝色涂画过又被黄色涂画过,那么这个格子就会变成绿色,用‘G’表示。
小Q已经有想画出的作品的样子,请你帮他计算一下他最少需要多少次操作完成这幅画。

输入描述:
第一行包含两个正整数N和M(1<=N,M<=50),表示画板的长宽。
接下来的N行包含N个长度为M的字符串,其中包含‘B’,‘Y’,‘G’,‘X’,分别表示蓝色,黄色,绿色,空白。整个表示小Q要完成的作品。

输出描述:
一个正整数,表示小Q最少需要多少次操作完成绘画。

输入

4 4
YXXB
XYGX
XBYX
BXXY

输出

3

思路

  现在已经有一幅成型的画了,我们要思考的是最少操作怎么还原这幅画,所以得用减法,比如找到画中符合斜率为-1和1的Y线或者B线将其还原成X。
  不管输入的矩阵是正方形还是长方形,都从第一行第一列的格子开始向右遍历所有格子,假设当前格子是array[i][j],分三种情况讨论:
1、当前格子是黄色‘Y’,说明这里必须有一次操作,操作数+1,那么右下找斜率为-1的直线,即一直找array[i+1][j+1]的格子(确保不出界):
  ①、如果array[i+1][j+1]的格子也是Y,那么将其标记为X还原;
  ②、如果是G,将其还原为G-Y即B。
然后继续往-1斜率找,直到遇到的格子既不是Y也不是G
2、类似Y的处理,当前格子是蓝色‘B’,说明这里必须有一次操作,操作数+1,那么左下找斜率为1的直线,即一直找array[i+1][j-1]的格子(确保不出界):
  ①、如果array[i+1][j-1]的格子也是B,那么将其标记为X还原;
  ②、如果是G,将其还原为G-B即Y。
然后继续往1斜率找,直到遇到的格子既不是B也不是G
3、当前格子是绿色‘G’,说明这里必须有两次操作,操作数+2,绿色得当黄色和蓝色两种同时处理,右下找斜率为-1的直线,左下找斜率为1的直线,然后处理同上述1和2。

代码

#include <iostream>
using namespace std;

int main(void) {
    // 记录结果:操作数(绘制路径数) 
    int ans = 0;

    // n*m,n行m列 
    int n, m;
    cin >> n >> m;
    char array[n][m];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> array[i][j];
        } 
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (array[i][j] == 'Y') {
                // 路径加一 
                ans++;

                int a = i + 1;
                int b = j + 1;
                while (a < n && b < m) {
                    // 只要不出界,就往右下遍历
                    if (array[a][b] == 'Y') {
                        array[a][b] = 'X';
                        a++;
                        b++;
                    } else if (array[a][b] == 'G') {
                        array[a][b] = 'B';
                        a++;
                        b++;
                    } else {
                        // 只有遇到Y和G才继续遍历,遇到X和B都停 
                        break;
                    } 
                }
            }
            if (array[i][j] == 'B') {
                // 蓝色处理类似黄色 
                ans++;
                int a = i + 1;
                int b = j - 1;
                while (a < n && b >= 0) {
                    // 只要不出界,就往左下遍历
                    if (array[a][b] == 'B') {
                        array[a][b] = 'X';
                        a++;
                        b--;
                    } else if (array[a][b] == 'G') {
                        array[a][b] = 'Y';
                        a++;
                        b--;
                    } else {
                        break;
                    } 
                }
            }
            if (array[i][j] == 'G') {
                // 绿色当黄色+蓝色处理 
                ans += 2;
                int a = i + 1;
                int b = j + 1;
                while (a < n && b < m) {
                    if (array[a][b] == 'Y') {
                        array[a][b] = 'X';
                        a++;
                        b++;
                    } else if (array[a][b] == 'G') {
                        array[a][b] = 'B';
                        a++;
                        b++;
                    } else {
                        break;
                    } 
                }
                int c = i + 1;
                int d = j - 1;
                while (c < n && d >= 0) {
                    if (array[c][d] == 'B') {
                        array[c][d] = 'X';
                        c++;
                        d--;
                    } else if (array[c][d] == 'G') {
                        array[c][d] = 'Y';
                        c++;
                        d--;
                    } else {
                        break;
                    } 
                }
            }
        } 
    }
    cout << ans << endl;
}

代码通过样例100%


第二题——贪吃的小Q

题意

小Q有M块巧克力,要在N天内吃完。小Q决定每天吃的巧克力数量不少于前一天吃的一半,又不想N天内的任何一天没有巧克力吃,请问小Q第一天最多能吃多少块巧克力。

输入描述:
两个正整数,表示天数N(N<=50000)和巧克力数量M(N<=M<=100000)。

输出描述:
一个正整数,表示小Q第一天最多能吃多少块巧克力

输入

3 7

输出

4

思路

  根据题意,最理想的情况当然是,最后一天只吃M/(2^N-1)块,倒数第二天吃最后一天的两倍,倒数第三天吃倒数第二天的两倍,这样第一天肯定能吃最多,问题是,巧克力足够还好说,如果不足够是没法这样吃的。
  由于巧克力可能数量不够的限制,我们不要从最后一天为1倒回去,而是从第一天往最后一天推,第二天永远是前一天的一半(如果前一天是奇数,则为一半+1,相当于四舍五入,比如前一天吃3,第二天得吃2,不能吃1),然后再把所有天数吃的巧克力总数加起来与M比较,如果比M小,说明符合题意。
  优化算法速率:
  ①、由于是第一天要吃最多,所以第一天往最后一天推的时候,第一天应该从大往小遍历(这样能提高找到答案的效率,因为从第一天只吃一块开始判断是没意义的)。
  ②、而且从大往小的这个“大”也未必要从M开始,比如输入样例4 13,如果从第一天吃13块开始判断,都是没意义的。这里考虑到最最理想情况也就是每天都是2的幂次数。比如四天分别吃8M/15、4M/15、2M/15、M/15这样,你会发现这种情况第一天也就比其他天加起来多了M/(2^N-1)块而已,
  所以我们从M/2+M/(2^N-1)开始遍历

代码

#include<iostream>
#include<math.h>
using namespace std;

int main(void) {
    int n, m;
    cin >> n >> m;
    int ans = m;
    // 计算多出来的块数 
    int ex = m/(pow(2,n)-1);
    // 若n为1,直接返回m 
    if (n > 1) {
        for (int i = m/2+ex; i >= 1; i--) {
            // i为第一天吃的块数
            int temp = i;
            // he保存各天数吃的巧克力总数 
            int he = i;
            for (int j = 1; j < n; j++) {
                if ((temp&1) == 0) {
                    temp = temp / 2;
                } else {
                    temp = temp / 2 + 1;
                }
                he += temp;
            }
            if (he <= m) {
                // 如果加起来的总数小于m,说明找到答案,停止循环,节省时间
                // 保存第一天吃的块数
                ans = i;
                break;
            }
        }
    }
    cout << ans << endl;
}

代码通过样例未知,>=80%


第三题——纸牌游戏

题意

牛和羊玩纸牌游戏,有n张牌,每一张牌写着数字a[i]。牛先抽牌,然后是羊,轮流抽,每次一张。因为得分等于抽到的纸牌数字总和,然后牛和羊都采取最优策略,游戏结束后牛得分减去羊的得分等于多少。

输入描述:
第一行为一个正整数n(1<=n<=10^5),表示纸牌的数量。
第二行为n个正整数a[i](1<=a[i]<=10^9),表示每张纸牌上的数字。
输出描述:
一个整数,表示游戏结束后牛得分减去羊的得分等于多少。

输入

3
2 7 4

输出

5

思路

  最优策略,所以每人每次都要挑数组中最大的那个数加到自己的分数中去,维护两个变量作为牛和羊的分数。
  然后对整个数组排序(我这里是降序快排),牛先抽,所以他的分数是,快排后的数组的所有奇数位上的数之和,羊的分数则是所有偶数位上的数之和。

代码

#include<iostream>
using namespace std;

void quicksort(int a[], int left, int right) {
    int i, j, temp;
    if (left > right) {
        return;
    }
    temp = a[left];
    i = left;
    j = right;
    while(i != j) {
        while(a[j]<=temp && i<j) 
            j--;
        while(a[i]>=temp && i<j)
            i++;
        if (i < j) {
            int num = a[i];
            a[i] = a[j];
            a[j] = num; 
        }
    }
    a[left] = a[i];
    a[i] = temp;
    quicksort(a, left, i-1);
    quicksort(a, i+1, right);
}
int main(void) {
    int n;
    scanf("%d", &n);

    int a[n];
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    quicksort(a, 0, n-1);

    int niu = 0, yang = 0;
    for (int i = 0; i <= n-1; i++) {
        if ((i&1) == 0) {
            // 如果为偶数位 
            niu += a[i];
        } else {
            yang += a[i];
        }
    }
    printf("%d\n", niu-yang);

    return 0;
}

代码通过样例100%


总结

难度其实不难,但是对我来说,在那种考试状态要冷静下来想出最优解法还是挺难的。
再接再厉!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值