在由 2D 网格表示的校园里有 n
位工人(worker
)和 m
辆自行车(bike
),n <= m
。所有工人和自行车的位置都用网格上的 2D 坐标表示。
我们为每一位工人分配一辆专属自行车,使每个工人与其分配到的自行车之间的曼哈顿距离最小化。
p1
和 p2
之间的曼哈顿距离为 Manhattan(p1, p2) = |p1.x - p2.x| + |p1.y - p2.y|
。
返回每个工人与分配到的自行车之间的曼哈顿距离的最小可能总和。
示例 1:
输入:workers = [[0,0],[2,1]], bikes = [[1,2],[3,3]]
输出:6
解释:
自行车 0 分配给工人 0,自行车 1 分配给工人 1 。分配得到的曼哈顿距离都是 3, 所以输出为 6 。
示例 2:
输入:workers = [[0,0],[1,1],[2,0]], bikes = [[1,0],[2,2],[2,1]]
输出:4
解释:
先将自行车 0 分配给工人 0,再将自行车 1 分配给工人 1(或工人 2),自行车 2 给工人 2(或工人 1)。如此分配使得曼哈顿距离的总和为 4。
提示:
0 <= workers[i][0], workers[i][1], bikes[i][0], bikes[i][1] < 1000
- 所有工人和自行车的位置都不相同。
1 <= workers.length <= bikes.length <= 10
思路:
先用二维矩阵记录每个工人到每辆车的距离,dp[i][j] = distance就表示工人 i 和车 j 的距离为distance。
然后问题就转化为:
在二维矩阵里每一行取一个数digit,
当前行取完 digit 之后别的行不能在 digit 在的这一列再取,
求所有行都取一个数后
所有这些取出来数的最小和。
暴力解就是回溯, 所有取法都试一次,时间复杂度是O(N!),
python比较慢不能过, C++和JAVA可以过。
所以python需要优化剪枝,用dp记录之前已经计算过的局部解,
在重复计算时直接读之前算过的答案。
class Solution(object):
def assignBikes(self, workers, bikes):
"""
:type workers: List[List[int]]
:type bikes: List[List[int]]
:rtype: int
"""
n, m = len(workers), len(bikes)
dis = [[0 for _ in range(m)] for _ in range(n)]
for w, worker in enumerate(workers):
xw, yw = worker[0], worker[1]
for b, bike in enumerate(bikes):
xb, yb = bike[0], bike[1]
dis[w][b] = abs(xb - xw) + abs(yb - yw)
def findRes(wid, usedbike):
if wid >= n:
return 0
state = (wid, tuple(sorted(list(usedbike))))
# print state
if state in dp: #以前算过
return dp[state]
else:
tmp = 9999999
print tmp
for bid in range(m):
if bid not in usedbike:
usedbike.add(bid)
t = dis[wid][bid] + findRes(wid + 1, usedbike)
usedbike.remove(bid)
tmp = min(tmp, t)
dp[state] = tmp
return tmp
usedbike = set()
dp = {}
return findRes(0, usedbike)