我最近完成了以下面试:
'机器人可编程为运行“a”,“b”,“c”......“n”公里,需要t a ,t b ,t c ... t n 分钟。一旦运行到程序设计的公里数,它必须关闭“m”分钟。
在“m”分钟之后,它可以再次被编程为运行另一个“a”,“b”,“c”......“n”公里。
你如何编程这个机器人在最短的时间内达到确切的公里数?'
我认为这是无界knapsack问题的变体,其中大小将是公里数和值,即完成每次伸展所需的时间。主要区别在于我们需要最小化而不是最大化价值。所以我使用了以下解决方案的等价物:http://en.wikipedia.org/wiki/Knapsack_problem#Unbounded_knapsack_problem 我在其中选择最小值。
最后,因为我们需要一个精确的解决方案(如果有的话),在算法为不同距离构建的地图上,我遍历每个机器人的编程距离,找到确切的距离和最短的时间。那些。
我认为机器人在两次运行之间的暂停是一个红色的鲱鱼,你只需要将它包含在你的计算中,但它不会影响所采用的方法。
我可能错了,因为我没有通过考试。我对预期的解决方案没有任何其他反馈。
编辑:也许我毕竟没错,因为不同的原因我失败了。我只是想验证我对这个问题的处理方法。
import static com.google.common.collect.Sets.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public final class Robot {
static final Logger logger = Logger.getLogger (Robot.class);
private Set<ProgrammedRun> programmedRuns;
private int pause;
private int totalDistance;
private Robot () {
//don't expose default constructor & prevent subclassing
}
private Robot (int[] programmedDistances, int[] timesPerDistance, int pause, int totalDistance) {
this.programmedRuns = newHashSet ();
for (int i = 0; i < programmedDistances.length; i++) {
this.programmedRuns.add (new ProgrammedRun (programmedDistances [i], timesPerDistance [i] ) );
}
this.pause = pause;
this.totalDistance = totalDistance;
}
public static Robot create (int[] programmedDistances, int[] timesPerDistance, int pause, int totalDistance) {
Preconditions.checkArgument (programmedDistances.length == timesPerDistance.length);
Preconditions.checkArgument (pause >= 0);
Preconditions.checkArgument (totalDistance >= 0);
return new Robot (programmedDistances, timesPerDistance, pause, totalDistance);
}
/**
* @returns null if no strategy was found. An empty map if distance is zero. A
* map with the programmed runs as keys and number of time they need to be run
* as value.
*
*/
Map<ProgrammedRun, Integer> calculateOptimalStrategy () {
//for efficiency, consider this case first
if (this.totalDistance == 0) {
return Maps.newHashMap ();
}
//list of solutions for different distances. Element "i" of the list is the best set of runs that cover at least "i" kilometers
List <Map<ProgrammedRun, Integer>> runsForDistances = Lists.newArrayList();
//special case i = 0 -> empty map (no runs needed)
runsForDistances.add (new HashMap<ProgrammedRun, Integer> () );
for (int i = 1; i <= totalDistance; i++) {
Map<ProgrammedRun, Integer> map = new HashMap<ProgrammedRun, Integer> ();
int minimumTime = -1;
for (ProgrammedRun pr : programmedRuns) {
int distance = Math.max (0, i - pr.getDistance ());
int time = getTotalTime (runsForDistances.get (distance) ) + pause + pr.getTime();
if (minimumTime < 0 || time < minimumTime) {
minimumTime = time;
//new minimum found
map = new HashMap<ProgrammedRun, Integer> ();
map.putAll(runsForDistances.get (distance) );
//increase count
Integer num = map.get (pr);
if (num == null) num = Integer.valueOf (1);
else num++;
//update map
map.put (pr, num);
}
}
runsForDistances.add (map );
}
//last step: calculate the combination with exact distance
int minimumTime2 = -1;
int bestIndex = -1;
for (int i = 0; i <= totalDistance; i++) {
if (getTotalDistance (runsForDistances.get (i) ) == this.totalDistance ) {
int time = getTotalTime (runsForDistances.get (i) );
if (time > 0) time -= pause;
if (minimumTime2 < 0 || time < minimumTime2 ) {
minimumTime2 = time;
bestIndex = i;
}
}
}
//if solution found
if (bestIndex != -1) {
return runsForDistances.get (bestIndex);
}
//try all combinations, since none of the existing maps run for the exact distance
List <Map<ProgrammedRun, Integer>> exactRuns = Lists.newArrayList();
for (int i = 0; i <= totalDistance; i++) {
int distance = getTotalDistance (runsForDistances.get (i) );
for (ProgrammedRun pr : programmedRuns) {
//solution found
if (distance + pr.getDistance() == this.totalDistance ) {
Map<ProgrammedRun, Integer> map = new HashMap<ProgrammedRun, Integer> ();
map.putAll (runsForDistances.get (i));
//increase count
Integer num = map.get (pr);
if (num == null) num = Integer.valueOf (1);
else num++;
//update map
map.put (pr, num);
exactRuns.add (map);
}
}
}
if (exactRuns.isEmpty()) return null;
//finally return the map with the best time
minimumTime2 = -1;
Map<ProgrammedRun, Integer> bestMap = null;
for (Map<ProgrammedRun, Integer> m : exactRuns) {
int time = getTotalTime (m);
if (time > 0) time -= pause; //remove last pause
if (minimumTime2 < 0 || time < minimumTime2 ) {
minimumTime2 = time;
bestMap = m;
}
}
return bestMap;
}
private int getTotalTime (Map<ProgrammedRun, Integer> runs) {
int time = 0;
for (Map.Entry<ProgrammedRun, Integer> runEntry : runs.entrySet()) {
time += runEntry.getValue () * runEntry.getKey().getTime ();
//add pauses
time += this.pause * runEntry.getValue ();
}
return time;
}
private int getTotalDistance (Map<ProgrammedRun, Integer> runs) {
int distance = 0;
for (Map.Entry<ProgrammedRun, Integer> runEntry : runs.entrySet()) {
distance += runEntry.getValue() * runEntry.getKey().getDistance ();
}
return distance;
}
class ProgrammedRun {
private int distance;
private int time;
private transient float speed;
ProgrammedRun (int distance, int time) {
this.distance = distance;
this.time = time;
this.speed = (float) distance / time;
}
@Override public String toString () {
return "(distance =" + distance + "; time=" + time + ")";
}
@Override public boolean equals (Object other) {
return other instanceof ProgrammedRun
&& this.distance == ((ProgrammedRun)other).distance
&& this.time == ((ProgrammedRun)other).time;
}
@Override public int hashCode () {
return Objects.hashCode (Integer.valueOf (this.distance), Integer.valueOf (this.time));
}
int getDistance() {
return distance;
}
int getTime() {
return time;
}
float getSpeed() {
return speed;
}
}
}
public class Main {
/* Input variables for the robot */
private static int [] programmedDistances = {1, 2, 3, 5, 10}; //in kilometers
private static int [] timesPerDistance = {10, 5, 3, 2, 1}; //in minutes
private static int pause = 2; //in minutes
private static int totalDistance = 41; //in kilometers
/**
* @param args
*/
public static void main(String[] args) {
Robot r = Robot.create (programmedDistances, timesPerDistance, pause, totalDistance);
Map<ProgrammedRun, Integer> strategy = r.calculateOptimalStrategy ();
if (strategy == null) {
System.out.println ("No strategy that matches the conditions was found");
} else if (strategy.isEmpty ()) {
System.out.println ("No need to run; distance is zero");
} else {
System.out.println ("Strategy found:");
System.out.println (strategy);
}
}
}
答案 0 :(得分:4)
稍微简化,让t i 是机器人运行距离d i 所花费的时间(包括停机时间)。假设t 1 / d 1 ≤...≤t n / d n 。如果t 1 / d 1 明显小于t 2 / d 2 且d 1 < / sub>和要运行的总距离D很大,然后分支和绑定可能优于动态编程。分支和边界解决整数规划公式
最小化Σ i t i x i
受制于
Σ i d i x i = D
∀ix i ∈ N
通过使用弛豫的值,其中x i 可以是任何非负实数作为指导。通过将x 1 设置为D / d ,后者很容易被验证为最多(t 1 / d 1 )D 1 和∀i≠1 x i = 0,并且至少(t 1 / d 1 )D,通过设置双程序的唯一变量为t 1 / d 1 。解决放松是绑定步骤;每个整数解都是一个分数解,所以最好的整数解需要时间至少(t 1 / d 1 )D。
分支步骤采用一个整数程序并将其拆分为两个,其解决方案一起覆盖原始的整个解空间。在这种情况下,一个可以有额外的约束x 1 = 0而另一个可以有额外的约束x 1 ≥1。看起来好像这会创建具有边约束的子问题,但事实上,我们可以删除第一个移动,或者通过d 1 减少D并将常数t 1 添加到目标。分支的另一个选项是添加约束x i =⌊D/ d i ⌋或x i ≤⌊D/ d i ⌋ - 1,需要将每次移动的重复次数推广到上限。
分支和绑定的主循环选择子问题,分支的集合之一,计算两个子问题的边界,并将它们放回集合中。蛮力的效率来自这样一个事实:当我们有一个具有特定价值的解决方案时,每个放松价值至少相当多的子问题都可以被抛弃。一旦收集以这种方式清空,我们就有了最佳的解决方案。
分支和绑定以及动态编程的混合是可能的,例如,通过DP计算小D的最佳解决方案,并使用这些值而不是已经解决的子问题上的分支。
答案 1 :(得分:1)
创建大小为m且0到m(m是距离)的数组:
a [i] =无限;
a [0] = 0;
a [i] = min {min {a [i-j] + t j + m,所有 j 在可能的公里数机器人中。和 j≠i }, t i 如果 i 可能是机器人的移动}
a [m]是可能的最低值。您还可以使用b
这样的数组来保存a[i]
选择。此外,如果[m] ==无限意味着它是不可能的。
编辑:我们可以通过创建有向图来另外解决它,我们的图表依赖于m
路径长度,图表标有{0..m}的节点,现在从节点0开始将它连接到所有可能的节点;表示如果你有一公里i
你可以连接0和v i 与权重t i ,除了节点0-> x,对于所有其他节点对于j> i,你应该将节点i-> j与权重 t ji + m 连接起来,并且ji在输入公里中可用。现在你应该找到从v 0 到v n 的最短路径。但是这个算法仍然是O(nm)。
答案 2 :(得分:0)
设G为期望的距离。
设n是没有暂停的最长距离。
设L = G / n(整数算术,丢弃分数部分)
设R = G mod n(即上述除法的余数)
让机器人运行它的最长距离(即n)L次,然后以最小量(即最小可用距离等于)的任何距离(a,b,c等)大于R或大于R)
要么我理解错误的问题,要么你都在想它
答案 3 :(得分:0)
我非常相信表现而不是说话。这是一个可能正在寻找你正在寻找的程序。如果它满足您的问题,请告诉我。只需复制,粘贴和运行该程序即可。您当然应该使用自己的数据集进行测试。
import java.util.Arrays;
public class Speed {
/***
*
* @param distance
* @param sprints ={{A,Ta},{B,Tb},{C,Tc}, ..., {N,Tn}}
*/
public static int getFastestTime(int distance, int[][] sprints){
long[] minTime = new long[distance+1];//distance from 0 to distance
Arrays.fill(minTime,Integer.MAX_VALUE);
minTime[0]=0;//key=distance; value=time
for(int[] speed: sprints)
for(int d=1; d<minTime.length; d++)
if(d>=speed[0] && minTime[d] > minTime[d-speed[0]]+speed[1])
minTime[d]=minTime[d-speed[0]]+speed[1];
return (int)minTime[distance];
}//
public static void main(String... args){
//sprints ={{A,Ta},{B,Tb},{C,Tc}, ..., {N,Tn}}
int[][] sprints={{3,2},{5,3},{7,5}};
int distance = 21;
System.out.println(getFastestTime(distance,sprints));
}
}