想象一下,你有3个水桶,但每个水桶都有一个洞。我正试着填满浴缸。浴缸所需的水量最低,可容纳的水量最多。当你带着水桶到达浴缸时,不清楚桶里有多少水,但你有一系列可能的值。
是否可以用水充分填充浴缸?
你差不多有3个范围(最小值,最大值),它们的总和是否会落在第4范围内?
例如: 铲斗1:5-10L 铲斗2:15-25L 铲斗3:10-50L
浴缸100-150L
是否有一些保证组合1 2和3可以在必要范围内填充浴缸?可以使用每个桶的倍数。
编辑:现在想象有50个不同的桶?答案 0 :(得分:1)
如果浴缸的容量不是很大(例如,不超过10 ^ 6),我们可以使用动态编程解决它。
<强>方法强>
初始化:备忘录[X] [Y]是一个记忆结果的数组。 X =桶的数量,Y =桶的最大容量。使用-1初始化memo [] []。
<强>代码:强>
bool dp(int bucketNum, int curVolume){
if(curVolume > maxCap)return false; // pruning extra branches
if(curVolume>=minCap && curVolume<=maxCap){ // base case on success
return true;
}
int &ret = memo[bucketNum][curVolume];
if(ret != -1){ // this state has been visited earlier
return false;
}
ret = false;
for(int i = minC[bucketNum]; i < = maxC[bucketNum]; i++){
int newVolume = curVolume + i;
for(int j = bucketNum; j <= 3; j++){
ret|=dp(j,newVolume);
if(ret == true)return ret;
}
}
return ret;
}
警告:代码未经过测试
答案 1 :(得分:1)
这是python中一个天真的递归解决方案,可以很好地工作(尽管它没有找到最佳解决方案):
def match_helper(lower, upper, units, least_difference, fail = dict()):
if upper < lower + least_difference:
return None
if fail.get((lower,upper)):
return None
exact_match = [ u for u in units if u['lower'] >= lower and u['upper'] <= upper ]
if exact_match:
return [ exact_match[0] ]
for unit in units:
if unit['upper'] > upper:
continue
recursive_match = match_helper(lower - unit['lower'], upper - unit['upper'], units, least_difference)
if recursive_match:
return [unit] + recursive_match
else:
fail[(lower,upper)] = 1
return None
def match(lower, upper):
units = [
{ 'name': 'Bucket 1', 'lower': 5, 'upper': 10 },
{ 'name': 'Bucket 2', 'lower': 15, 'upper': 25 },
{ 'name': 'Bucket 3', 'lower': 10, 'upper': 50 }
]
least_difference = min([ u['upper'] - u['lower'] for u in units ])
return match_helper(
lower = lower,
upper = upper,
units = sorted(units, key = lambda u: u['upper']),
least_difference = min([ u['upper'] - u['lower'] for u in units ]),
)
result = match(100, 175)
if result:
lower = sum([ u['lower'] for u in result ])
upper = sum([ u['upper'] for u in result ])
names = [ u['name'] for u in result ]
print lower, "-", upper
print names
else:
print "No solution"
它为100-150打印“无解”,但对于100-175,它提供了5x桶1,5x桶2的解决方案。
答案 2 :(得分:0)
假设您说每个水桶的“范围”是它到达浴缸时可能产生的水量,您关心的是它们是否可能填满浴缸......
只需取每个桶的“最大值”并求它们。如果这是你认为浴缸被“填充”的范围,那么就可以。
答案 3 :(得分:0)
更新:
鉴于桶可以多次使用,我觉得我们正在寻找一对方程的解决方案。
给定桶x,y和z我们想要找到a,b和c:
a*x.min + b*y.min + c*z.min >= bathtub.min
和
a*x.max + b*y.max + c*z.max <= bathtub.max
回复:http://en.wikipedia.org/wiki/Diophantine_equation
如果bath.min和bathtub.max都是a,b和c的最大公约数的倍数,那么有无限多的解(即我们可以填充浴缸),否则没有解决方案(即我们可以从不填满浴缸。)
答案 4 :(得分:0)
最初,您的目标范围是Bathtub.Range。
每次向解决方案添加存储桶实例时,都会减少剩余存储桶的目标范围。
例如,使用示例桶和桶:
目标范围= 100..150
假设我们想在候选解决方案中添加Bucket1。那就给了我们
目标范围= 95..140
因为如果解决方案中的其余桶总数
因此,这可以让您快速检查候选解决方案是否有效:
TargetRange = Bathtub.Range
foreach Bucket in CandidateSolution
TargetRange.Min -= Bucket.Min
TargetRange.Max -= Bucket.Max
if TargetRange.Min == 0 AND TargetRange.Max >= 0 then solution found
if TargetRange.Min < 0 or TargetRange.Max < 0 then solution is invalid
这仍然存在一个问题 - 你如何提出候选解决方案?
蛮力会尝试所有可能的桶组合。
答案 5 :(得分:0)
这可以通过change making problem的多个应用来解决。
每个Bucket.Min值是货币面额,Bathtub.Min是目标值。
当您通过更改算法找到解决方案时,再应用一个约束:
总和(解决方案中的每个Bucket.Max)&lt; = Bathtub.max
如果不满足此约束,请抛弃此解决方案并查找另一个。这可能需要更改标准的更改算法,以便在发现其他解决方案不合适时尝试其他解决方案。
答案 6 :(得分:0)
这是我找到最佳解决方案(最少数量的桶)的解决方案。它将最大值与最小值之比进行比较,以确定填充桶的最佳铲斗数量。
private static void BucketProblem()
{
Range bathTub = new Range(100, 175);
List<Range> buckets = new List<Range> {new Range(5, 10), new Range(15, 25), new Range(10, 50)};
Dictionary<Range, int> result;
bool canBeFilled = SolveBuckets(bathTub, buckets, out result);
}
private static bool BucketHelper(Range tub, List<Range> buckets, Dictionary<Range, int> results)
{
Range bucket;
int startBucket = -1;
int fills = -1;
for (int i = buckets.Count - 1; i >=0 ; i--)
{
bucket = buckets[i];
double maxRatio = (double)tub.Maximum / bucket.Maximum;
double minRatio = (double)tub.Minimum / bucket.Minimum;
if (maxRatio >= minRatio)
{
startBucket = i;
if (maxRatio - minRatio > 1)
fills = (int) minRatio + 1;
else
fills = (int) maxRatio;
break;
}
}
if (startBucket < 0)
return false;
bucket = buckets[startBucket];
tub.Maximum -= bucket.Maximum * fills;
tub.Minimum -= bucket.Minimum * fills;
results.Add(bucket, fills);
return tub.Maximum == 0 || tub.Minimum <= 0 || startBucket == 0 || BucketHelper(tub, buckets.GetRange(0, startBucket), results);
}
public static bool SolveBuckets(Range tub, List<Range> buckets, out Dictionary<Range, int> results)
{
results = new Dictionary<Range, int>();
buckets = buckets.OrderBy(b => b.Minimum).ToList();
return BucketHelper(new Range(tub.Minimum, tub.Maximum), buckets, results);
}