使用Dijkstra降低成本?

如何解决使用Dijkstra降低成本?

我花了几个小时来回答一个所谓的“轻松”练习问题,并认为我可以提出一个更可靠的问题。希望能得到反馈。

问题仍然存在:

您需要配备一张办公桌,以便一个人一直在这里连续24小时。您可以雇用6个人来这样做,但是您希望将成本降到最低。工作时间小于等于8小时的任何人每小时赚15美元,工作时间大于8小时的任何人每小时赚20美元。可以使用哪种贪婪算法来最小化成本? (例如,确定是否要雇用2个人,每个人要使用12个小时,请雇用1个人来24小时,请3个人来分别雇用8小时,等等)?

所以我知道Dijkstra是一种“贪心”算法,可以让我们使用加权边。

我理解问题的症结所在-我可以使用Dijkstra来找到一套可以最大程度降低24小时轮班费用的套件。 (例如,从顶层节点将子节点分解为“ 1人移位”,“ 2人移位”,“ 3人移位”,“ 4人移位”,“ 5人移位”,“ 6人移位“ ...然后在其他子节点中列出所有组合。边缘的“权重”是成本。我想找到“最便宜的”路径,但是显然这很麻烦,因为我必须列出所有可能的分组(即5个和6个安全警卫)及其费用。

In [4]:
shift = {}
shift["1_guard"] = {}
shift["2_guards"] = {}
shift["3_guards"] = {}
shift["4_guards"] = {}
shift["5_guards"] = {}
shift["6_guards"] = {}
#at each step we're doing a brute force attack to figure out ok ... if we have x guards,whats the breakdown of the total costs possible?
shift["1_guard"]["Shifts_Filled"] = (24 * 20)

shift["2_guards"]["1_hour_23_hours"] = ((15 * 1)+ (20 * 23))
shift["2_guards"]["2_hour_22_hours"] = ((15 * 2)+ (20 * 22))
shift["2_guards"]["3_hour_21_hours"] = ((15 * 3)+ (20 * 21))
shift["2_guards"]["4_hour_20_hours"] = ((15 * 4)+ (20 * 20))
shift["2_guards"]["5_hour_19_hours"] = ((15 * 5)+ (20 * 19))
shift["2_guards"]["6_hour_18_hours"] = ((15 * 6)+ (20 * 18))
shift["2_guards"]["7_hour_17_hours"] = ((15 * 7)+ (20 * 17))
shift["2_guards"]["8_hour_16_hours"] = ((15 * 8)+ (20 * 16))
shift["2_guards"]["9_hour_15_hours"] = ((15 * 9)+ (20 * 15))
shift["2_guards"]["10_hour_14_hours"] = ((15 * 10)+ (20 * 14))
shift["2_guards"]["11_hour_13_hours"] = ((15 * 11)+ (20 * 13))
shift["2_guards"]["12_hour_12_hours"] = ((15 * 12)+ (20 * 12))
#you dont need to do more than this because it will be one of these combos (it doesnt matter which guard works which shift)

shift["3_guards"]["1_hour_1_hour_22_hours"] = ((15 * 1) + (15 * 1) + (20*22)
#fill in for every combination of hours 3 guards could have
                                               
shift("4_guards")["1_hour_1_hour_1_hour_20_hours"] = ((15 * 1) + (15 * 1) (15 * 1) + (20*22)
#fill in for every combination of hours 3 guards could have

def find_lowest_cost_node(costs):
    lowest_cost = float("inf")
    lowest_cost_node = None
    # Go through each node.
    for node in costs:
        cost = costs[node]
        # If it's the lowest cost so far and hasn't been processed yet...
        if cost < lowest_cost and node not in processed:
            # ... set it as the new lowest-cost node.
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node
start_time = time.perf_counter()

# Find the lowest-cost node that you haven't processed yet.
node = find_lowest_cost_node(costs)
# If you've processed all the nodes,this while loop is done.
while node is not None:
    cost = costs[node]
    # Go through all the neighbors of this node.
    neighbors = shift[node]
    for n in neighbors.keys():
        new_cost = cost + neighbors[n]
        # If it's cheaper to get to this neighbor by going through this node...
        if costs[n] > new_cost:
            # ... update the cost for this node.
            costs[n] = new_cost
            # This node becomes the new parent for this neighbor.
            parents[n] = node
    # Mark the node as processed.
    processed.append(node)
    # Find the next node to process,and loop.
    node = find_lowest_cost_node(costs)

print("Cost from the start to each node:")
print(costs)

print(time.perf_counter() - start_time,"seconds")
dijkstras_time = time.perf_counter() - start_time
                                                      
# the costs table
infinity = float("inf")
costs = {}
costs["1_guard"] = 
costs["2_guards"] = 
costs["3_guards"] = 
costs["4_guards"] = infinity


# the parents table
#need help here
parents = {}
parents[""] = "NYC"
parents[""] = "NYC"
parents[""] = "NYC"
#all the ones below a certain threshold should have None*
parents[""] = None


processed = []

我要这样做正确吗?反馈我的代码会很有帮助。

解决方法

我认为Dijkstra在这里不一定是最有用的,因为它产生了从A到B的成本最低的路径。然后,如果您真的想使用它,则可以让中间节点表示状态,即node在计划了08:00至8AM(当前警卫在午夜开始)之后,G表示状态(08:00,00:00)。这样,最佳路径将是

(00:00,00:00) -> (01:00,00:00) -> ... -> (08:00,00:00) -> (09:00,08:00) -> ...

您实际上正在做的是动态编程,您可以在其中将问题分解为较小的子问题,并将其求解为最优。

现在,我在上面提到的新状态下使用了一些代码。这将搜索空间减少到仅325个节点。实际上,您的状况很好,只是关于我没有得到(也不需要)的父母的部分。相反,我使用带有元组键的字典,并让该值表示成本。

infinity = float("inf")

nodes = {
    (current_hour,last_guard_started_hour): infinity
    for current_hour in range(25)
    for last_guard_started_hour in range(25)
    if last_guard_started_hour <= current_hour
}
start = current = (0,0)
nodes[start] = 0
processed = []

然后,如果您像正方形(x,y)栅格那样看它,则除非您在边界处,否则邻居就是(x-1,y),(x+1,(x,y-1),y + 1)处的节点。

def find_neighbours(current_node):
    current_hour,last_guard_started_hour = current_node
    
    # Neighbours are when either the guard started earlier/later or the current
    # hour progresses/regresses
    neighbours = []
    if current_hour > 0 and last_guard_started_hour != current_hour:
        neighbours.append((current_hour - 1,last_guard_started_hour))
    if current_hour < 24:
        neighbours.append((current_hour + 1,last_guard_started_hour))

    if last_guard_started_hour > 0:
        neighbours.append((current_hour,last_guard_started_hour - 1))
    if last_guard_started_hour < current_hour:
        neighbours.append((current_hour,last_guard_started_hour + 1))

    return neighbours

然后您可以逐渐知道已知的解决方案直到逐渐更新节点,从而使当前保护措施处于最佳状态,因此无需重新计算。

def get_cheapest_for_hour(hour):
    candidates = { n: nodes[n] for n in nodes
                   if n[0] == hour }

    # Get the entry with the lowest cost,but also prefer longer shifts
    node = min(candidates,key=lambda k: (nodes[k],k[1]))
    return node

def set_cost(node):
    hour,last_guard_started_hour = node
    if hour == 0 and last_guard_started_hour == 0:
        return

    cost = 0
    current_guard_hours_worked = hour - last_guard_started_hour

    # If the current guard starts just now,we get the cheapest solution for the
    # previous hour and add wages to that
    if current_guard_hours_worked == 0:
        nodes[node] = nodes[get_cheapest_for_hour(hour - 1)] + 15
        return
        
    if current_guard_hours_worked > 8:
        cost += current_guard_hours_worked * 20
    else:
        cost += current_guard_hours_worked * 15

    cost += nodes[(hour - current_guard_hours_worked,hour - current_guard_hours_worked)]
    nodes[node] = cost

现在我保留了该功能,我认为它非常聪明!

def find_lowest_cost_node():
    lowest_cost = infinity
    lowest_cost_node = None
    # Go through each node.
    for node in nodes:
        cost = nodes[node]
        # If it's the lowest cost so far and hasn't been processed yet...
        if cost < lowest_cost and node not in processed:
            # ... set it as the new lowest-cost node.
            lowest_cost = cost
            lowest_cost_node = node
    return lowest_cost_node

在这里,我简化了无需父母的代码

while current is not None:
    cost = nodes[current]
    # Go through all the neighbours of the current node
    for n in find_neighbours(current):
        # Update their costs
        set_cost(n)
    
    processed.append(current)
    current = find_lowest_cost_node()

print("Cost from the start to each node:")
print(nodes)

print(f"Optimal schedule cost: {nodes[(24,24)]}")
print("The optimal schedule is:")

node = (24,24)
while True:
    hour,last_guard_started_hour = node
    current_guard_hours_worked = hour - last_guard_started_hour

    node = get_cheapest_for_hour(hour - current_guard_hours_worked)
    if node[0] == 0:
        break

    print(f"From {node[1]}:00 to {node[0]}:00")

现在,我还没有包括最多6个警卫,但是显然可以通过将元组扩展为(current_hour,last_guard_started_hour,number_of_guards_used)来做到这一点。祝你好运!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-