3月27日做了华为笔试,3道题2小时。当时没有拍照,现在凭记忆将题目和代码叙述一遍,方便后人。前面将把三道题分别列一下,供后来者自己做。在后面说明一下自己的写法
第一题:题目说的比较复杂,读懂题意之后大致是,9个字符一组,每组的第一个字符是标志位,后面8个字符是地址。如果标志位是0,地址逆序,标志位是1地址不变。输入说明:一个字符串,有多组字符,中间没有空格。输出说明:输出最后的地址,每组地址用空格隔开,最后一个输出不需要空格。时间:C/C++1秒其他2秒
第二题:简而言之就是TSP问题。蜂巢在坐标(0,0)的位置,有五处花丛,蜜蜂从蜂巢出发,要把五处花丛的花蜜采完再回到蜂巢,最短距离是多少。输入说明:一行输入,10个数分别是五处花丛的坐标(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5),用空格隔开。输出说明:输出最短距离,距离向下取整。时间:C/C++5秒其他10秒
第三题:切水果游戏。有一个40×50的方格,里面有n(1≤n≤36)个水果,每一刀可以横切,竖切以及左斜切与右斜切四种方式。想要切完所有水果,最少需要多少刀。输入说明:第一行是说过个数n,接下来的n行是水果的横纵坐标。输出说明:输出最少需要的刀数。(PS:原题有图,这里无图解释一下切割方式,横切就是所有x相同的水果可以一刀切完,纵切就是y相同,左斜切就是x-y相同,右斜切就是x+y相同)。时间:C/C++3秒其他6秒
下面是各题做法和思路:
第一题:题目说的比较复杂,读懂题意之后大致是,9个字符一组,每组的第一个字符是标志位,后面8个字符是地址。如果标志位是0,地址逆序,标志位是1地址不变。输入说明:一个字符串,有多组字符,中间没有空格。输出说明:输出最后的地址,每组地址用空格隔开,最后一个输出不需要空格。
解答:第一题很简单,9个一组得读取,判断第一个是0还是1即可。5分钟内即可AC。
-
# -*- coding:utf8 -*-
-
n = int(input())
-
strs = input()
-
for i
in range(n):
-
s = strs[
9*i:
9*i+
9]
# 9个一组得读取
-
if s[
0] ==
'0':
-
s = s[
1:]
-
s = s[::
-1]
# 逆序
-
else:
-
s = s[
1:]
-
print(s, end=
' ')
# 空格输出
第二题:简而言之就是TSP问题。蜂巢在坐标(0,0)的位置,有五处花丛,蜜蜂从蜂巢出发,要把五处花丛的花蜜采完再回到蜂巢,最短距离是多少。输入说明:一行输入,10个数分别是五处花丛的坐标(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5),用空格隔开。输出说明:输出最短距离,距离向下取整。
解答:一开始就想到了全排列之后贪心算法取最小,虽然觉得方法太low了,但是让我一下子写出蚁群之类的觉得记忆模糊就很纠结。后来发现这道题给了10秒的运行时间,妥妥的决定用全排列了。思路:先用全排列的方式获取蜜蜂访问5个花丛的所有可能顺序,之后计算每个路径长度取最小。
-
# -*- coding:utf8 -*-
-
from math
import sqrt
-
line = input().strip().split()
-
n = list(map(int, line))
-
n = [int(i)
for i
in line]
-
nums = [[
0,
0], [n[
0],n[
1]], [n[
2],n[
3]], [n[
4],n[
5]], [n[
6],n[
7]], [n[
8],n[
9]]]
-
# 以下为插入的方式获取全排列的代码。没看过别人的,自己想到的。
-
# 后来看网上说,递归获取全排列更常见,有兴趣的可以自己去搜一下。
-
order = [[
1]]
-
for i
in range(
2,
6):
-
lens = len(order)
-
j =
0
-
while j < lens:
-
for k
in range(i
-1):
-
tmp = order[j][:]
#
-
order.append(tmp)
-
order[
-1].insert(k, i)
-
order[j].append(i)
-
j +=
1
-
# 接下来是制作距离矩阵
-
dist = [[
0] *
6
for i
in range(
6)]
-
for i
in range(
6):
-
for j
in range(
6):
-
if dist[i][j] ==
0:
-
dist[i][j] = sqrt((nums[i][
0]-nums[j][
0])**
2 + (nums[i][
1]-nums[j][
1])**
2)
-
else:
-
dist[i][j] = dist[j][i]
-
# 贪心算法取最小
-
minVal =
0
-
for path
in order:
-
sums = dist[
0][path[
0]]
-
for i
in range(
4):
-
sums += dist[path[i]][path[i+
1]]
-
sums += dist[path[
4]][
0]
-
if minVal > sums
or minVal ==
0:
-
minVal = sums
-
print(int(minVal))
第三题:切水果游戏。有一个40×50的方格,里面有n(1≤n≤36)个水果,每一刀可以横切,竖切以及左斜切与右斜切四种方式。想要切完所有水果,最少需要多少刀。输入说明:第一行是说过个数n,接下来的n行是水果的横纵坐标。输出说明:输出最少需要的刀数。(PS:原题有图,这里无图解释一下切割方式,横切就是所有x相同的水果可以一刀切完,纵切就是y相同,左斜切就是x-y相同,右斜切就是x+y相同)。时间:C/C++3秒其他6秒。
解答:当时用的贪心算法,只通过了70%,后来想到了动态规划算法,虽然没试过但是个人感觉应该可以AC。和LeetCode零钱兑换问题差不多的思路。
-
# -*- coding:utf8 -*-
-
# 40 * 50的方格
-
from random
import randint
-
# 动态规划算法。对于一个点,四种切法去除被切除的点即可获得下一次的点集。加上1即可
-
def dp(points):
-
if len(points) <=
1:
-
return len(points)
-
first = points[
0]
-
row = [i
for i
in points
if i[
0] != first[
0]]
-
cntRow = dp(row)
-
col = [i
for i
in points
if i[
1] != first[
1]]
-
cntCol = dp(col)
-
left = [i
for i
in points
if i[
2] != first[
2]]
-
cntLeft = dp(left)
-
right = [i
for i
in points
if i[
3] != first[
3]]
-
cntRight = dp(right)
-
return
1 + min(cntRow, cntCol, cntLeft, cntRight)
-
-
-
# 贪心算法。假设只能选择一种方式切,选择刀数最少的
-
def greedyOne(points):
-
x = [i[
0]
for i
in points]
-
y = [i[
1]
for i
in points]
-
l = [i[
2]
for i
in points]
-
r = [i[
3]
for i
in points]
-
return min(len(set(x)), len(set(y)), len(set(l)), len(set(r)))
-
-
-
n = int(input())
-
points = []
-
for i
in range(n):
-
line = input().strip().split()
-
x = int(line[
0])
-
y = int(line[
1])
-
l = y - x
-
r = x + y
-
points.append([x, y, l, r])
-
'''
-
# 此部分为随机获取点值,确定自己的动态规划算法是否最优
-
n = 15
-
for i in range(10):
-
points = []
-
for j in range(n):
-
x = randint(0,40)
-
y = randint(0,50)
-
l = y - x
-
r = x + y
-
points.append([x, y, l, r])
-
res1 = dp(points)
-
res2 = greedyOne(points)
-
print('dp is %d, greedy is %d'%(res1, res2))
-
if res1 > res2:
-
print(points)
-
'''