旅行商问题
【问题描述】假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。
【输入形式】城市数目,以及城市之间的距离
【输出形式】所有路径之中的最小值
【样例输入】
4
0,10,15,20
10,0,35,25
15,35,0,30
20,25,30,0
【样例输出】
80
【样例说明】
第一行说明有4个城市;第2至5行说明一个城市与其他城市的距离,其中城市到其自身的距离为0,不可达的城市之间的距离为0。
import itertools
n = int(input()) # 输入城市数目
distances = [] # 存储城市之间的距离
for i in range(n):
row = input().split(',')
distances.append([int(x) for x in row])
# 枚举所有可能的路径
all_paths = list(itertools.permutations(range(n)))
# 计算所有可能路径的长度
min_distance = float('inf') # 初始化最小距离为正无穷大
for path in all_paths:
distance = 0
for i in range(n):
distance += distances[path[i]][path[(i+1)%n]] # 计算路径长度
if distance < min_distance:
min_distance = distance
if __name__ == '__main__':
print(min_distance)
邮局选址问题
【问题描述】对一个以XY轴表达的城市里,n个居民点散乱分布,居民点位置可以用坐标(x,y)表示,任意两点(x1,y1)(x2,y2)间距离可以用| x1-x1|+|y1-y2|度量,居民希望在城市中选择建立邮局的最佳位置,使得n个居民点到邮局的距离总和最小
【输入形式】居民点数目,以及居民点的坐标
【输出形式】最小的距离总和
【样例输入】
3
3 3
1 6
4 9
【样例输出】9
【样例说明】第一行说明有3个居民点,第2-4行说明各个居民点的坐标
n=int(input())
lx=[]
ly=[]
for i in range(n):
x,y=map(int,input().split())
lx.append(x)
ly.append(y)
lx=sorted(lx)#排序
ly=sorted(ly)
if n%2!=0:#奇数,求中位数
z=int((n-1)/2)
x0=lx[z]
y0=ly[z]
else:#偶数
z=int(n/2)
x0=int((lx[z]+lx[z-1])/2)
y0=int((ly[z]+ly[z-1])/2)#题目要int
sumx=0
sumy=0
for j in lx:
p=abs(x0-j)
sumx=sumx+p
for k in ly:
q=abs(y0-k)
sumy=sumy+q
print(sumx+sumy)
最优合并问题
【问题描述】给定k个排好序的序列s1,s2,…,sk,用2路合并算法将这k个序列合并成一个序列。假设所采用的2路合并算法合并两个长度分别为m和n的序列需要m+n-1次比较。试设计一个算法确定合并这个序列的最优合并顺序,使所需要的总比较次数最少。
【输入形式】序列数目,以及各个序列中的元素数目。
【输出形式】最少的总比较次数
【样例输入】
4
5 12 11 2
【样例输出】
52
【样例说明】第一行输入说明共有4个序列,第二行说明各个序列中的元素数目。
n = int(input())
a = list(map(int, input().split(' ')))
w=int(0)
i=int(0)
a.sort()#从小到大排序
while(i<n-1):#
w=w+a[i]+a[i+1]-1;#2个长度分别为m和n的序列需要m+n -1次比较
a[i]=a[i]+a[i+1];
a[i+1]=0
i+=1
a.sort()
print(w)
# print(b)
堆排序
【问题描述】排序问题: 给定一个无序序列,采用”堆排序“方法对序列升序排序。
【输入形式】无序的整数序列
【输出形式】升序的整数序列
【样例输入】12,11,13, 5, 6,7
【样例输出】5, 6, 7,11,12,13
【样例说明】以逗号隔开的序列, 程序内需要转化为整数序列
import heapq
def heap_sort():
nums = input().split(",")
nums = [int(num) for num in nums]
heap = []
for num in nums:
heapq.heappush(heap, num) # 将元素加入堆中
sorted_nums = []
while heap:
sorted_nums.append(heapq.heappop(heap)) # 从堆中取出最小元素,并加入已排序列表
print(end="")
print(*sorted_nums, sep=",")
# 测试
if __name__ == '__main__':
heap_sort()
布线问题
【问题描述】
印刷电路板将布线区域划分成n*m个方格,精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。在布线时,电路只能沿直线或直角布线。为了避免线路相交,已经布了线的方格不允许其他线穿过。对给定的电路板,找出最短的布线路径。
【输入形式】
方阵的行数、列数、布线区域方阵(其中不能通过的地方输入1,能通过的地方输入0)、起点坐标、终点坐标
【输出形式】
线路长度以及线路包含的方格坐标
【样例输入】
6 6
0 0 1 0 0 0
0 0 1 1 0 0
0 0 0 0 1 0
0 0 0 1 1 0
1 0 0 0 1 0
1 1 1 0 0 0
1 2
4 3
【样例输出】
4
1,2 > 2,2 > 3,2 > 4,2 > 4,3
【样例说明】
第1行输入方阵的行数、列数
第2-7行输入方阵元素,不能通过的地方输入1,能通过的地方输入0
第8行输入起点坐标
第9行输入终点坐标
所有元素用空格分隔, 且坐标索引从1开始!!
import numpy as np
from queue import Queue
class Node:
def __init__(self, row, col):
self.row = row
self.col = col
def findPath(start, finish, n, m, grid): # 起始点,结束点,路径长,路径
global path, PathLen1
if (start.row == finish.row) and (start.col == finish.col):
Pathlen = 0
return True
grid[0, 0:m + 1] = grid[n + 1, 0:m + 1] = 1 # 设置四周的围墙
grid[0:n + 1, 0] = grid[0:n + 1, m + 1] = 1
offset = [Node(0, 1),Node(1, 0), Node(0, -1), Node(-1, 0)] # 右,下,左,上
NumofNbers = 4
here = start
nbr = Node(0, 0)
grid[start.row][start.col] = 2
Q = Queue(maxsize=0) # 创建一个队列
while True:
for i in range(NumofNbers): # 当前点的四周的点
nbr.row = here.row + offset[i].row
nbr.col = here.col + offset[i].col
if grid[nbr.row, nbr.col] == 0: # 该方格未被标记
grid[nbr.row, nbr.col] = grid[here.row, here.col] + 1
if (nbr.row == finish.row) and (nbr.col == finish.col): # 完成布线直接结束循环
break
nbr1 = Node(nbr.row, nbr.col)
Q.put(nbr1) # 将当前点加入队列
if nbr.row == finish.row and nbr.col == finish.col: # 完成布线结束循环
break
if Q.empty(): # 队列为空,表示无解
return False
here = Q.get() # 下一个拓展结点
Pathlen = grid[finish.row, finish.col] - 2
PathLen1 = Pathlen
here = finish
for j in range(Pathlen - 1, -1, -1): # 回溯寻找路径
path.append(Node(here.row, here.col)) # 将当前点加入路径
for i in range(NumofNbers):
nbr.row = here.row + offset[i].row
nbr.col = here.col + offset[i].col
if grid[nbr.row, nbr.col] == j + 2: # 找到上一个坐标
break
here = Node(nbr.row, nbr.col) # 更新为上一个坐标
return True
def main():
global path, PathLen1
n, m = map(int, input().split(' '))
grid = np.zeros((n + 2, m + 2), dtype=int)
for i in range(1, n + 1):
grid[i, 1:n + 1] = np.array(input().split(), dtype=int)
start_x, start_y = map(int, input().split(' '))
finish_x, finish_y = map(int, input().split(' '))
start = Node(start_x, start_y)
finish = Node(finish_x, finish_y)
if findPath(start, finish, n, m, grid):
print(PathLen1)
path.append(start)
path = np.flipud(path)
for i in range(len(path) - 1):
print(path[i].row, end=',')
print(path[i].col, end='-->')
print(path[-1].row, end=',')
print(path[-1].col)
else:
print("没有路径!")
global path, PathLen1
PathLen1 = 0 # 用于保存路线长度
path = [] # 保存路线
if __name__ == '__main__':
main()
汽车加油问题
【问题描述】一辆汽车加满油后可以行驶n千米。旅途中有k个加油站。若要使沿途的加油次数最少,设计一个有效的算法,采用贪心算法,编程计算并输出最少加油次数,以及指出应在那些加油站停靠加油。
【输入形式】两行标准输入,数字通过空格分隔
【输出形式】将编程计算出的最少加油次数,以及哪些加油站,输出到文件ouput.txt。如果无法到达目的地,则输出“No Solution”。
【样例输入】
7 7
1 2 3 4 5 1 6 6
【样例输出】
4
3 4 6 7
【样例说明】
第一行标准输入有2个正整数n和k,表示汽车加满油后可行驶n km,且旅途中有k个加油站。
第二行标准输入有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。第0个加油站表示出发地,汽车已加满油。第k+1个加油站表示目的地。
# 这是一个示例 Python 脚本。
# 按 Shift+F10 执行或将其替换为您的代码。
# 按 双击 Shift 在所有地方搜索类、文件、工具窗口、操作和设置。
def fuel(n,k,distance):#n 满油路程 k 加油站数量 distance 距离
nTemp = n #当前油量可行驶路程
move=0 #将要行驶路程
count=0 #计算加油次数
locate=[] #加油站坐标
for i in range(len(distance)):
move+=distance[i]
if(move<nTemp):#如果下一段路程小于油量可行驶路程,则行驶
nTemp-=distance[i]
move=0
else:
nTemp=n
nTemp -= distance[i]
count+=1
move=0
locate.append(i)
return count,locate
if __name__ == '__main__':
# n=7
# k=7
# distance = [1,2,3,4,5,1,6,6]
n, k = map(int, input().split())
temp = input().split(" ")
distance=list(map(int,temp))
for i in distance:
if (i > n):
print("No solution!")
exit()
count,locate=fuel(n,k,distance)
print(count)
for i in locate:
print(i,end=" ")
最大团问题
【问题描述】
给定一个无向图G=(V,E),若U为V子集,请对任意的顶点u, v为U的元素,有边(u,v)为E元素,则称U为G的一个完全子图。G的完全子图U是一个团,当且仅当U不包含在G的更大的完全子图中。G的最大团则指包含定点数最多的团。对给定的无向图,找出最大团中顶点的个数。
【输入形式】
G的邻接矩阵
【输出形式】
第一行输出最大团顶点个数,第二行输出最大团中的顶点
【样例输入】
0,1,1,0,0
1,0,1,1,1
1,1,0,1,1
0,1,1,0,1
0,1,1,1,0
【样例输出】
最大团顶点个数: 4
最大团为: [0, 1, 1, 1, 1]
【样例说明】输入的邻接矩阵表明图中有5个顶点,矩阵元素为1,则行、列对应的顶点有边相连,否则没有边相连。矩阵元素之间通过逗号隔开。举例:假设5个顶点分别为ABCDE,那么A与B、C相连。最终求得,最大团中包含4个节点,为BCDE。
import numpy as np
def bron_kerbosch_pivot(r, p, x, graph, cliques):
if not any((p, x)):
cliques.append(r)
else:
# Choose a pivot vertex u in union of p and x
u = max(p.union(x), key=lambda v: sum(graph[v]))
# For each vertex v in p that is adjacent to u
for v in p.difference(graph[u]):
# Bron-Kerbosch with pivot on v
bron_kerbosch_pivot(r.union({v}), p.intersection(graph[v]), x.intersection(graph[v]), graph, cliques)
# Remove v from p and add to x
p.discard(v)
x.add(v)
def find_cliques(graph):
cliques = []
bron_kerbosch_pivot(set(), set(graph.keys()), set(), graph, cliques)
return cliques
def max_clique(graph):
cliques = find_cliques(graph)
max_clique = max(cliques, key=len)
return max_clique, len(max_clique)
# 读取输入邻接矩阵
adjacency_matrix = []
while True:
try:
line = input().strip()
row = list(map(int, line.split(',')))
adjacency_matrix.append(row)
except:
break
graph = {i: set(np.nonzero(row)[0]) for i, row in enumerate(adjacency_matrix)}
# 求解最大团
max_clique, max_clique_size = max_clique(graph)
# 输出结果
if __name__ == '__main__':
print("最大团顶点个数:", max_clique_size)
print("最大团为:", max_clique)
最长公共子序列
【问题描述】
若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。如果给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。现给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},要求使用动态规划算法思想,找出X和Y的最长公共子序列。
【输入形式】输入以空格分割的字符,第一行对应第一条序列,第二行对应第二条序列。
【输出形式】字符数组形式的最长公共子序列。
【样例输入】
z x y
x y y
【样例输出】
['x', 'y']
【样例说明】
第一行输入为第一条序列,包含z x y三个字符;输出为最长公共子序列,包含两个字符,以数组形式输出。
def lcs(X, Y):
m = len(X)
n = len(Y)
# 创建二维列表c,用于存储最长公共子序列的长度
c = [[0] * (n+1) for _ in range(m+1)]
# 创建二维列表b,用于记录最长公共子序列的方向
b = [[0] * (n+1) for _ in range(m+1)]
for i in range(1, m+1):
for j in range(1, n+1):
if X[i-1] == Y[j-1]:
c[i][j] = c[i-1][j-1] + 1
b[i][j] = "↖"
elif c[i-1][j] >= c[i][j-1]:
c[i][j] = c[i-1][j]
b[i][j] = "↑"
else:
c[i][j] = c[i][j-1]
b[i][j] = "←"
return c, b
def print_lcs(X, b, i, j):
if i == 0 or j == 0:
return []
if b[i][j] == "↖":
sub_lcs = print_lcs(X, b, i-1, j-1)
sub_lcs.append(X[i-1])
return sub_lcs
elif b[i][j] == "↑":
return print_lcs(X, b, i-1, j)
else:
return print_lcs(X, b, i, j-1)
# 测试
if __name__ == '__main__':
X = input().split()
Y = input().split()
c, b = lcs(X, Y)
lcs_result = print_lcs(X, b, len(X), len(Y))
print( lcs_result)
棋盘覆盖问题
【问题描述】给定一个2k×2k的棋盘(具体图例见教材),有一个特殊棋格,拥有一个特殊棋格的棋盘称为特殊棋盘。现要用四种L型骨牌(具体图例见教材)覆盖特殊棋盘上除特殊棋格外的全部棋格,不能重叠,找出覆盖方案。
【输入形式】在屏幕上输入棋盘大小及特殊方格所在行号和列号
【输出形式】输出使用L型骨牌进行棋盘覆盖结果
【样例输入】
2
1 2
【样例输出】
2 -1 3 3
2 2 1 3
4 1 1 5
4 4 5 5
【样例说明】
输入:第一行输入整数k表示棋盘大小为2的k次幂,若k为2,则棋盘大小为4行4列;第二行输入特殊方格所在的行号和列号,以空格分隔
输出:使用L型骨牌进行棋盘覆盖结果,由3个相同的数表示同一个L型骨牌,不同的骨牌用不同的数字表示。数字的大小表示棋盘覆盖的顺序。特殊方格在棋盘的第1行第2列,用-1表示。各整数间以空格分隔。
def chessBoard(tr,tc,dr,dc,size):
if size == 1:
return
global tile
global board
tile += 1
t = tile
s = size//2
if dr<tr+s and dc<tc+s:
chessBoard(tr,tc,dr,dc,s)
else:
board[tr+s-1][tc+s-1] = t
chessBoard(tr,tc,tr+s-1,tc+s-1,s)
if dr < tr + s and dc >= tc + s:
chessBoard(tr, tc+s, dr, dc, s)
else:
board[tr+s-1][tc+s] = t
chessBoard(tr, tc+s, tr+s-1, tc+s, s)
if dr >= tr + s and dc < tc + s:
chessBoard(tr+s, tc, dr, dc, s)
else:
board[tr + s][tc + s - 1] = t
chessBoard(tr+s, tc, tr + s, tc + s - 1, s)
if dr >= tr + s and dc >= tc + s:
chessBoard(tr+s, tc+s, dr, dc, s)
else:
board[tr + s][tc + s] = t
chessBoard(tr+s, tc+s, tr+s, tc+s, s)
def show_chess(board):
n = len(board)
for i in range(n):
for j in range(n):
print(board[i][j], end=" ")
print('')
tile = 0
size = int(input())
n= pow(2,size)
if __name__ == '__main__':
dr,dc= map(int,input().split())
board=[[0 for x in range(n)]for y in range(n)]
board[dr-1][dc-1]=-1
chessBoard(0,0,dr-1,dc-1,n)
show_chess(board)