携程2017春季招聘编程题 - 后台开发

总结:上机课老师不让请假,只得在机房答题,结果环境比较吵,很多选择题都没有耐心算完,后来电脑又没电了,差不多花了 20min 取来电源才继续开始做,此时已经完全没有心思了,勉强做了下去。第一道编程题当时想到了比较繁琐的 dp ,第二题是八数码问题,为了防止 TLE ,用了 A 结果写搓了,调到最后都没找到错误,附加题也没有看。

快结束时身后很多人人来走去,估计要被判为作弊了,清白的就成为历史了。。。

官方题解

1. 乘积最大

题目链接

题意

有一个整数n,将n分解成若干个不同自然数之和,问如何分解能使这些数的乘积最大,输出这个乘积m

思路Ⅰ - dp

想到一个比较笨的 dp dp[i][j] 表示i分解的最大一个数为j时能分解的最多的数, last[i][j] 表示当前状态的次大数,然后找出能分解的最多的数的路径计算即可得到答案,如果能分解的最多的数一样,则找最大数最小的(因为此时所有数相差最小,即乘积最大,由均值不等式可得)。

代码

#include <cstring>
#include <iostream>

using namespace std;

int num, dp[53][53], last[53][53], cnt, rem, tmp;
long long ans;

int main(){
    while(cin >> num) {
        memset(dp, -1, sizeof(dp));
        for(int i = 1; i <= num; ++i) {
            dp[i][i] = 1;
            last[i][i] = 0;
        }
        for(int i = 2; i <= num; ++i) {
            for(int j = 1; j <= i; ++j) {
                if(dp[i][j] != -1) {
                    for(int k = j + 1; i + k <= num; ++k) {
                        if(dp[i + k][k] < dp[i][j] + 1) {
                            dp[i + k][k] = dp[i][j] + 1;
                            last[i + k][k] = j;
                        }
                    }
                }
            }
        }
        cnt = 1;
        rem = num;
        for(int j = 1; j < num; ++j) {
            if(dp[num][j] > cnt) {
                cnt = dp[num][j];
                rem = j;
            }
        }

        ans = 1;
        while(num > 0) {
            ans *= rem;

            tmp = num;
            num -= rem;
            rem = last[tmp][rem];
        }
        cout << ans << "\n";
    }
    return 0;
}

思路Ⅱ - dp

结束后看了题解,才注意到 dp[i][j] 表示i分解成的数最大为j时的最大乘积,然后直接进行转移,即可求出答案。这样设状态很方便,环境和心情影响真是太大了。。。

代码

#include <cstring>
#include <iostream>

using namespace std;

int num, dp[53][53], last[53][53], cnt, rem, tmp;
long long ans;

int main(){
    while(cin >> num) {
        memset(dp, -1, sizeof(dp));
        for(int i = 1; i <= num; ++i) {
            dp[i][i] = 1;
            last[i][i] = 0;
        }
        for(int i = 2; i <= num; ++i) {
            for(int j = 1; j <= i; ++j) {
                if(dp[i][j] != -1) {
                    for(int k = j + 1; i + k <= num; ++k) {
                        if(dp[i + k][k] < dp[i][j] + 1) {
                            dp[i + k][k] = dp[i][j] + 1;
                            last[i + k][k] = j;
                        }
                    }
                }
            }
        }
        cnt = 1;
        rem = num;
        for(int j = 1; j < num; ++j) {
            if(dp[num][j] > cnt) {
                cnt = dp[num][j];
                rem = j;
            }
        }

        ans = 1;
        while(num > 0) {
            ans *= rem;

            tmp = num;
            num -= rem;
            rem = last[tmp][rem];
        }
        cout << ans << "\n";
    }
    return 0;
}

2. 通过考试

题目链接

题意

拼图,是一个老少皆宜的益智游戏,在打乱的3*3的范围中,玩家只能每次将空格(0)和相邻的数字格(上、下、左、右)交换,最终调整出一个完整的拼图。
完整拼图为:
1 2 3
4 5 6
7 8 0

思路 - BFS

C++ 给的空间非常小,所以为了避免 MLE ,就用了 A 算法,结果写搓了。。。结果一改就成 MLE ,官方提供的模版简直就是坑人,应该坚定地按照自己的想法写。
最后换成 int AC

代码

#include <iostream>
#include <map>
#include <queue>

using namespace std;

const int dx[] = {-3, 1, 3, -1};

struct Node {
    int status, cnt;

    Node() {}

    Node(int sstatus, int ccnt): status(sstatus), cnt(ccnt) {}
}cur;

int index, tmp, status, dir;
map<int, bool> mp;
queue<Node> q;
int goal = 123456789;
int s[11];

void getDir() {
    dir = 0;
    if(index > 2) {
        dir |= 1;
    }
    if(index % 3 != 2) {
        dir |= 2;
    }
    if(index <7) {
        dir |= 4;
    }
    if(index %3 != 0) {
        dir |= 8;
    }
}

int bfs(int numbers) {
    q.push(Node(numbers, 0));
    mp[numbers] = true;
    while(!q.empty()) {
        cur = q.front();
        q.pop();
        if(cur.status == goal) {
            return cur.cnt;
        }

        for(int i = 8; i >= 0; --i) {
            s[i] = cur.status % 10;
            if(s[i] == 9) {
                index = i;
            }
            cur.status /= 10;
        }
        getDir();
        for(int i = 0; i < 4; ++i) {
            tmp = index + dx[i];
            if(((dir & (1 << i)) != 0) && 0 <= tmp && tmp < 9) {
                swap(s[index], s[tmp]);
                status = 0;
                for(int j = 0; j < 9; ++j) {
                    status = status * 10 + s[j];
                }
                if(!mp[status]) {
                    q.push(Node(status, cur.cnt + 1));
                    mp[status] = true;
                }
                swap(s[index], s[tmp]);
            }
        }
    }
    return -1;
}

int main() {
    status = 0;
    for(int i = 0; i < 9; ++i) {
        scanf("%d", &tmp);
        if(tmp == 0) {
            tmp = 9;
        }
        status = status * 10 + tmp;
    }
    printf("%d\n", bfs(status));
    return 0;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值