华东师范大学数据科学与工程学院第八届“云计算与大数据”夏令营机试时间是8:30-11:30,共6道题,在陆老师负责的学院自己的OJ平台上进行。OJ平台使用体验良好。
给一串整数,有些数字是0,把0换成正整数,是的整个数组非递减且字典序最小。
输入:第一行一个整数n,表示数组元素个数;第二行n个整数。
输出:替换0之后的非递减数组,或者无解输出-1。
样例输入:
5
0 0 1 2 0
样例输出:
1 1 1 2 2
思路:因为要字典序最小,贪心,每一个0都让其等于前一个数的值,需要考虑第一个数是0的情况,第一个数要换成1;还有无解的情况,出现左边的数大于右边的数。(我这个2个情况一开始都没考虑,WA了2次)
AC代码:
#include
#include
using namespace std;
int n, a[1005];
int main() {
freopen("排序.txt", "r", stdin);
scanf("%d", &n);
bool f = true;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i-1] > a[i] && a[i] != 0) {
f = false;
break;
}
if (i == 1 && a[i] == 0) a[i] = 1;
if (a[i] == 0) {
a[i] = a[i-1];
}
}
if (f == false) {
printf("-1\n");
return 0;
}
for (int i = 1; i <= n; i++) {
printf("%d%c", a[i], i ==n?'\n':' ');
}
return 0;
}
初始数为0,每次2个+ - * / 的操作,选择一个,最后得到的数要最大。
样例输入:
3
+1 *3
+2 *40
-3 /2
样例输出:
37
样例解释:第一次选+1,0+1=1;第二次选*40,1*40=40;第三次选-3,40-3=37
数据范围:操作数的范围是1-10的整数
思路:贪心,每次选运算之后结果最大的,需要注意的就是字符串读入的处理。
代码:
#include
#include
#include
using namespace std;
int oper(int x, int y, char op) {
if (op == '*') return x*y;
if (op == '+') return x+y;
if (op == '-') return x-y;
if (op == '/') return x/y;
return 0;
}
int n;
int main() {
freopen("选择运算.txt", "r", stdin);
scanf("%d", &n);
string a, b;
int cur = 0;
for (int i = 1; i <= n; i++) {
cin >> a >> b;
int aa = 0;
if (a.size() == 2) {
aa = a[1]-'0';
} else {
aa = (a[1]-'0')*10+a[2]-'0';
}
int bb = 0;
if (a.size() == 2) {
bb = b[1]-'0';
} else {
bb = (b[1]-'0')*10+b[2]-'0';
}
cur = max(oper(cur, aa, a[0]), oper(cur, bb, b[0]));
}
printf("%d\n", cur);
return 0;
}
上面的代码应该是能AC的,但我AC不是提交的上面的代码,当时因为一个变量写错了一直WA,担心贪心得不到最优解,使用了递归把所有的运算都走了一遍(数据比较弱)
AC代码:
#include
#include
#include
#include
using namespace std;
int oper(int x, int y, char op) {
if (op == '*') return x*y;
if (op == '+') return x+y;
if (op == '-') return x-y;
if (op == '/') return x/y;
return 0;
}
int n;
vector<int> na;
vector<int> nb;
vector<char> oa;
vector<char> ob;
const int INF = 0x3f3f3f3f;
int ans = -INF;
void dfs(int cur, int id) {
if (id == n) {
ans = max(ans, cur);
return;
}
int t = oper(cur, na[id], oa[id]);
dfs(t, id+1);
t = oper(cur, nb[id], ob[id]);
dfs(t, id+1);
}
int main() {
freopen("选择运算.txt", "r", stdin);
scanf("%d", &n);
string a, b;
int cur = 0;
for (int i = 1; i <= n; i++) {
cin >> a >> b;
int aa = 0;
if (a.size() == 2) {
aa = a[1]-'0';
} else {
aa = (a[1]-'0')*10+a[2]-'0';
}
na.push_back(aa);
oa.push_back(a[0]);
int bb = 0;
if (b.size() == 2) {
bb = b[1]-'0';
} else {
bb = (b[1]-'0')*10+b[2]-'0';
}
nb.push_back(bb);
ob.push_back(b[0]);
}
dfs(0, 0);
printf("%d\n", ans);
return 0;
}
给定n和m,求0—(n-1)这n个数从小到大全排列的第m个。
样例输入:
4 3
样例输出:
0213
样例解释:由0-3组成的全排列依次有:0123、0132、0213、0231、0312、0321……第3个数是0213
思路:直接暴力递归(再次证明数据规模不大),需要注意0在最前面的情况。
AC代码:
#include
#include
using namespace std;
typedef long long ll;
int n, m;
bool vis[11], fi = false;
ll ans = 0, cnt = 0;
void dfs(int id, ll cur) {
if (fi == true) {
return;
}
if (id == n) {
cnt++;
}
if (cnt == m) {
fi = true;
ans = cur;
return;
}
for (int i = 0; i < n; i++) {
if (vis[i] == false) {
vis[i] = true;
dfs(id+1, cur*10+i);
vis[i] = false;
}
}
}
int main() {
scanf("%d%d", &n, &m);
ll cur = 0;
dfs(0, cur);
ll t = 1;
for (int i = 1; i < n; i++) {
t *= 10;
}
if (ans < t) {
printf("0");
}
printf("%lld\n", ans);
return 0;
}
判断给定的无向图是不是二分图
输入:第一行一个数表示顶点个数n,下面n行,每行若干个数,第 i i i行表示与顶点 i i i相邻的顶点,以 − 1 -1 −1结束。
样例输入:
4
1 3 -1
0 2 -1
1 3 -1
0 2 -1
样例输出:
true
思路:dfs的应用二分图匹配
AC代码:
#include
#include
#include
using namespace std;
const int N = 1005;
vector<int> g[N];
int n;
int color[N];
bool ans = true;
void dfs(int x, int c) {
if (ans == false) return ;
color[x] = c;
for (int i = 0; i < g[x].size(); i++) {
int y = g[x][i];
if (color[y] == c) {
ans = false;
return;
}
if (color[y] == 0)
dfs(y, -c);
}
}
int main() {
freopen("二分图.txt", "r", stdin);
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int t = 0;
while (1) {
scanf("%d", &t);
if (t == -1) break;
g[i].push_back(t);
}
}
for (int i = 0; i < n; i++) {
if (color[i] == 0) {
dfs(i, 1);
}
}
if (ans) printf("true\n");
else printf("false\n");
return 0;
}
给一个长度为n的数组,划分成m个不为空的子数组,m个子数组中元素和最大的定义为这种划分方式的值,求所有划分方式的最小值
输入:第一行2个数,n和m;第二行n个数
输出:所有划分方式的最小值
样例输入:
5 2
7 2 5 10 8
样例输出:
18
样例解释:划分成2个数组,比如 [ 7 ] [7] [7]和 [ 2 , 3 , 10 , 8 ] [2,3,10,8] [2,3,10,8],这种划分的值是2+3+10+8=23;或者 [ 7 , 2 ] [7,2] [7,2]和 [ 3 , 10 , 8 ] [3,10,8] [3,10,8],这种划分的值是 m a x ( 7 + 2 , 3 + 10 + 8 ) = 21 max(7+2,3+10+8)=21 max(7+2,3+10+8)=21,输出的是所有划分的最小值。
思路:还是暴力,把所有划分情况枚举出来,得到每个划分的值,然后求最小值(比较菜,只会暴力)需要注意 i n t int int型会WA,我开了 l o n g long long l o n g long long
AC代码:
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 1005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll a[N], sum[N];
int n, m;
ll ans = INF;
void dfs(vector<int> t, int id) {
if (t.size() == m-1) {
ll ma = 0;
int left = 0, right = 0;
for (int i = 0; i <= m-2; i++) {
right = t[i];
ma = max(ma, sum[right]-sum[left]);
left = right;
}
ma = max(ma, sum[n] - sum[right]);
ans = min(ma, ans);
return ;
}
for (int i = id+1; i <= n-1; i++) {
dfs(t, i);
t.push_back(i);
dfs(t, i);
}
}
int main() {
freopen("分割数组.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
sum[i] = sum[i-1]+a[i];
}
vector<int> t;
dfs(t, 0);
printf("%lld\n", ans);
return 0;
}
给一个二叉树,每个节点的值是0或者1,删除所有子树节点值为0的的节点,输出删除之后的二叉树
输入:第一行一个整数表示层次遍历二叉树的结点的值,-1表示该节点为空
输出:删除之后层次遍历二叉树的结果
样例输入:
15
1 0 1 1 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1
样例输入:
1 0 1 1 -1 -1 -1 -1 -1
样例解释:
思路:dfs,如果当前节点及其子树节点的值全部为0,标记一下,之后层次遍历输出的时候判断标记即可
AC代码:
#include
#include
#include
using namespace std;
const int N = 10005;
struct Node {
int left, right, val;
} a[N];
int cnt = 0, n;
bool vis[N];
int dfs(int x) {
if (a[x].val == -1) return 0;
int t = a[x].val;
t += dfs(a[x].left);
t += dfs(a[x].right);
if (t == 0) vis[x] = false;
return t;
}
int main() {
freopen("二叉树.txt", "r", stdin);
scanf("%d", &n);
int t;
queue<int> q;
q.push(0);
for (int i = 1; i <= n; i++) {
scanf("%d", &t);
int x = q.front(); q.pop();
a[x].val = t;
if (t != -1) {
a[x].left = ++cnt;
a[x].right = ++cnt;
q.push(a[x].left);
q.push(a[x].right);
}
}
for (int i = 0; i <= cnt*2; i++) {
vis[i] = true;
}
t = dfs(0);
if (t == 0) vis[0] = false;
while (!q.empty()) q.pop();
if (vis[0] == true)q.push(0);
while (!q.empty()) {
int x = q.front();q.pop();
if (vis[x] == true) printf("%d ", a[x].val);
else printf("-1 ");
if (a[x].val == -1 || vis[x] == false) {
continue;
}
q.push(a[x].left);
q.push(a[x].right);
}
return 0;
}
机试的题涉及的知识点都是一些基础的数据结构和算法,如递归,bfs,dfs,二分图等,题目虽然没给数据范围,但数据规模并不大。很多题我提交了几次都WA了,后来再回过头来重新思考AC了,有些代码复制完之后直接提交了,忘了注释,WA了感觉很可惜,所以最后我的罚时还是比较严重的,第一个AC的拿了4个题的第一,差距还是非常大的。