100分值题
- 宽度最小的子矩阵
- 部门人力分配
- 电脑病毒感染
- 会议室占用时间段
- 路口最短时间问题
- 5G网络建设
宽度最小的子矩阵
- 给定一个n行 * m列的矩阵;
- 给定一个k个整数的数组k_list;
- 在n*m的矩阵中找一个宽度最小的子矩阵,该子矩阵包含k_list中所有的整数;
输入描述:
第一行输入n,m 两个整数;
后续n行每行输入 m个数据;
输入k值;
输入个整数
输出描述:
最小宽度值,若找不到,则输出-1
示例1
输入:
2 5
1 2 2 3 1
2 3 2 3 2
3
1 2 3
输出:
2
说明,
矩阵第0、3列包含了1、2、3;
矩阵第3、4列包含了1、2、3
示例2
输入:
2 5
1 2 2 3 1
1 3 2 3 4
3
1 1 4
输出:
5
思路:
- 滑动的子矩阵
- 从第一列起始,找一个宽度最小的子矩阵;
- 从第二列开始,找一个宽度最小的子矩阵;
- 依次到最后一列…
- 以上的宽度每次取最小值
class MinWidth:
def solution(self, n, m, matrix, k_list):
k_dict = self.to_dict(k_list)
min_width = float("inf")
# 类似双指针
for start_idx in range(m):
for end_idx in range(start_idx, m):
temp_list = []
# 获取当前子矩阵的所有元素
for i in range(n):
temp_list.extend(matrix[i][start_idx:end_idx+1])
temp_dict = self.to_dict(temp_list)
# 集合操作
flag = True
for key in k_dict:
if key in temp_dict and k_dict[key] <= temp_dict[key]:
continue
else:
flag = False
break
if flag:
min_width = min(min_width, end_idx - start_idx + 1)
break
print(min_width)
def to_dict(self, alist):
dict_ = {}
for i in alist:
dict_[i] = dict_.get(i, 0) + 1
return dict_
if __name__ == '__main__':
min_width = MinWidth()
while True:
try:
n, m = list(map(int, input().strip().split()))
matrix = []
for i in range(n):
matrix.append(list(map(int, input().strip().split())))
k = int(input().strip())
k_list = list(map(int, input().strip().split()))
min_width.solution(n, m, matrix, k_list)
except KeyboardInterrupt:
break
 
部门人力分配
- requirements表示开发需求数组,每个值表示当前需求的月数,所有需求需要在m个月内完成;
- 每个月最多有2个需求完成开发;人力安排后每个月人力是固定的;
- 在满足需求开发进度的情况下,每个月需要的最小人力是多少?
输入描述:
第一行输入m
第二行输入requirements 数组, 值>=1 长度为n;
1<=n/2<=m<=n<=10000
输出描述:
输出部门需要的人力?
示例1
输入:
3
3 5 3 4
输出:
6
说明:
开发时间为5个月的需求在一个月内完成,则需要5个人;
3 3 合并到一个月完成,需要6个人力;
3 4合并到一个月完成,需要7个人力;
4 5合并到一个月完成,需要9个人力;
示例2
输入:
3
3 3 4 5 6
输出:
8
示例3
输入:
3
3 3 4 5 6 2
输出:
思路:
- n个需求,n个月完成需要的人力较少,m个月完成人力增加;
- n个需求在m个月内完成,当n==m时,取requirements的最大值;
- n>m时,requirements升序排序,依次取出不需要合并的最大值放入temp_list,直到n==m的情况;
- 剩余需要合并的数对,利用双指针进行两两合并(最大值组合一个最小值),求的和放入temp_list;
- 最终 temp_list 长度会等于m,此时取temp_list的最大值即可;
class LeastResource:
def solution(self, requirements, m):
n = len(requirements)
requirements.sort()
temp_list = []
if n == m:
result = max(requirements)
print(result)
else:
while n / 2 < m:
temp_list.append(requirements.pop())
n -= 1
m -= 1
# 剩余需求 需要两两组合
self.merge(temp_list, requirements)
result = max(temp_list)
print(result)
def merge(self, temp_list, requirements):
cur_n = len(requirements)
pre = 0
cur = cur_n - 1
while pre < cur:
cur_sum = requirements[pre] + requirements[cur]
temp_list.append(cur_sum)
pre += 1
cur -= 1
if __name__ == '__main__':
least_resource = LeastResource()
while True:
try:
m = int(input().strip())
requirements = list(map(int, input().strip().split()))
least_resource.solution(requirements, m)
except KeyboardInterrupt:
break
二分法
最小人力范围在requirements的最大值—最大值+次最大值 之间;
m = int(input())
nums = [int(x) for x in input().split(" ")]
nums.sort()
def cal(k, nums, length) :
low = 0
high = length - 1
months = 0
while (True) :
if(low > high):
break
else :
if (nums[low] + nums[high] > k) :
high -= 1
else :
low += 1
high -= 1
months+=1
return months
low = nums[len(nums)-1]
high = nums[len(nums)-1] + nums[len(nums)-2]
result = -1
while (True) :
if(low > high):
break
else :
k = int((low + high) / 2)
if (cal(k, nums, len(nums)) <= m) :
high = k - 1
result = k
else :
low = k + 1
print(result)
电脑病毒感染
- 一个局域网内有n台电脑,编号为 0 -> n-1,电脑之间病毒感染时间用t表示;
- 现在网络内已有一台电脑被病毒感染;
- 求其感染所有其他电脑最少的时间,若最后有电脑不会感染,则返回-1;
- 数组times 表示一台电脑把相邻的电脑感染所用的时间;
- path[i] = {i, j, t} 表示 电脑i 感染 电脑j 所用的时间t;
输入描述:
第一行输入n 在[1, 200]
第二行输入m, 表示m条网络;
后m行,每行输入i,j,t, 1<=i,j<=n
最后一行输入携带病毒的电脑编号;
输出描述:
感染全部电脑的最少时间,不能感染全部输出-1
示例1
输入:
4
3
2 1 1
2 3 1
3 4 1
2
输出:
2
思路
- 单源最短路径
n = int(input())
count = int(input())
time = [float('inf') for i in range(n)]
matrix=[[0 for i in range(3)] for j in range(count)]
for j in range(count):
nums = [int(x) for x in input().split(" ")]
matrix[j][0] = nums[0]
matrix[j][1] =nums[1]
matrix[j][2] = nums[2]
start = int(input())
time[start-1] = 0
for i in range(n):
for j in range(count):
if (time[matrix[j][0]-1] + matrix[j][2] < time[matrix[j][1]-1]) :
time[matrix[j][1]-1] = time[matrix[j][0]-1] + matrix[j][2]
result = 0
i=0
while(True):
if(i>=n):
print(result)
break
else :
if (time[i] == float('inf')) :
print(-1)
break
if(time[i]>result):
result = time[i]
i+=1
会议室占用时间段
meetings = [[1,4], [2,5],[7,9], [14,18]]
def merge(meetings) :
sorted(meetings,key=lambda x: (x[1],x[0]))
result = []
result.append(meetings[0])
cur = result[0]
i=1
while(True):
if(i>=len(meetings)):
break
else :
if (cur[1] >= meetings[i][0] and cur[1] <= meetings[i][1]) :
cur[1] = meetings[i][1]
elif(cur[1] > meetings[i][1]):
pass
else :
result.append(meetings[i])
cur = meetings[i]
i+=1
print(result)
return result
merge(meetings)
路口最短时间问题
directions = [[-1,0],[0,1],[1,0],[0,-1]]
def calcTime(lights, timePerRoad, rowStart, colStart, rowEnd, colEnd) :
result = [[[float('inf') for i in range(4)] for j in range(colEnd+1)] for k in range(rowEnd+1)]
pq = queue.PriorityQueue()
for i in range(4):
pq.put([0, [rowStart, colStart, i, 0]])
result[rowStart][colStart][i] = 0
while (True) :
if(pq.qsize()<=0):
break
else :
point_t = pq.get()
point = point_t[1]
if (point[3] > result[point[0]][point[1]][point[2]]) :
continue
for i in range(4):
if (not(directions[i][0] == 1 and directions[i][1] == 0)) :
new_dir = (point[2] + i) % 4
new_x = point[0] + directions[new_dir][0]
new_y = point[1] + directions[new_dir][1]
if (new_x >= 0 and new_x < len(lights) and new_y >= 0 and new_y < len(lights[new_x])) :
new_speed = point[3] + timePerRoad
if (not(directions[i][0] == 0 and directions[i][1] == 1)):
new_speed += lights[point[0]][point[1]]
if (new_speed < result[new_x][new_y][new_dir]) :
result[new_x][new_y][new_dir] = new_speed
pq.put([new_speed, [new_x, new_y, new_dir, new_speed]])
return min(min(result[rowEnd][colEnd][0],result[rowEnd][colEnd][1]), result[rowEnd][colEnd][2])
lights = [[1,2,3],[4,5,6],[7,8,9]]
timePerRoad = 60
rowStart = 0
colStart = 0
rowEnd = 2
colEnd = 2
print(calcTime(lights,timePerRoad, rowStart,colStart, rowEnd, colEnd))
5G网络建设
- 选取n个地点建设5G基站,地点编号1 -> n;
- 各个基站之间使用光纤连接,设计算法计算连通所有基站的最小成本;
- 基站的连通具有传递性,A->B连通,B->C连通,则A->C连通;
输入描述:
第一行输入基站个数n, 0< n <=20;
第二行输入已具备光纤连接的基站对数m;
第三行开始的m行,格式为 X Y Z P,X Y表示基站编号 1-n且不相等,Z表示XY之间的光纤成本(0, 100),P表示是否已存在光纤连接,0未连接,1已连接;
输出描述:
输出最小的建设成本,无法建设完成输出-1;
示例1
输入:
3
3
1 2 3 0
1 3 1 0
2 3 5 0
输出:
4
说明:只需在1、2及2、3之间建设光纤
示例2
输入:
3
1
1 2 5 0
输出:
-1
示例3
输入:
3
3
1 2 3 0
1 3 1 0
2 3 5 1
输出:
1
class UF:
def __init__(self, n):
self.root = [i for i in range(n+1)]
self.rank = [1 for i in range(n+1)]
self.count = 0
def find(self,x):
if (x == self.root[x]):
return x
self.root[x] = self.find(self.root[x])
return self.root[x]
def union(self,x, y):
self.root[self.find(x)] = self.find(y)
self.count+=1
def get_count(self):
return self.count
n = int(input())
m = int(input())
uf = UF(n)
networks = []
for i in range(m):
data = [int(x) for x in input().split(" ")]
if (data[3] == 1):
if (uf.find(data[0]) != uf.find(data[1])):
uf.union(data[0], data[1])
else:
networks.append([data[0],data[1],data[2]])
sorted(networks, key=lambda x : x[2])
result = 0
i=0
while(True):
if(i>=len(networks)):
break
else:
if (uf.find(networks[i][0]) != uf.find(networks[i][1])):
uf.union(networks[i][0], networks[i][1])
result += networks[i][2]
if (uf.get_count() == n - 1):
break
i+=1
if(uf.get_count() != n - 1):
result = -1
print(result)