总结:上机课老师不让请假,只得在机房答题,结果环境比较吵,很多选择题都没有耐心算完,后来电脑又没电了,差不多花了 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;
}