这个答案也会给出工作代码,这次是 PHP。
一些重要的观察:
- 即使给定的示例从不会在任何天平的任一侧放置一个以上的天平,也允许多个天平位于天平的一侧;
- 不能保证只有一个根余额,房间里可能有几个分离的堆栈;
- 输入格式允许一个天平放置在多个其他天平上,或者在同一天平一侧放置多次,甚至放置在其自身上。假设此类和其他循环输入将被视为无效;
- 条件 “选择在最低天平上放置额外重量的方式” 相当于说 “您只能在每个天平的一侧添加重量,不能同时添加"
定义了四个函数:
-
parseInput 接受输入字符串并返回以逻辑方式表示数据的对象数组;
-
addWeights 获取余额的索引 (ID) 并计算应在其哪一侧添加权重,并将该权重存储在新属性中。该计算使用递归来计算位于该天平任一侧的所有天平的权重,在这些天平与添加的权重平衡之后。如果检测到循环,它会抛出错误,因此也可以防止无限递归;
-
balance 访问所有余额,如果尚未平衡,则调用上述 addWeights。这将涵盖多个 root 平衡配置;
-
outputString 采用完整的结构并以预期的输出格式返回一个字符串。
数据结构是对象对的数组。示例数据将转换为以下内容,并在计算过程中添加 addedWeight 属性:
[
[
{ 'weight' => 0, 'balances' => [1], 'addedWeight' => 0 },
{ 'weight' => 0, 'balances' => [2], 'addedWeight' => 14 }
], [
{ 'weight' => 0, 'balances' => [], 'addedWeight' => 10 },
{ 'weight' => 0, 'balances' => [3], 'addedWeight' => 0 }
], [
{ 'weight' => 3, 'balances' => [], 'addedWeight' => 0 },
{ 'weight' => 0, 'balances' => [], 'addedWeight' => 3 }
], [
{ 'weight' => 0, 'balances' => [], 'addedWeight' => 0 },
{ 'weight' => 0, 'balances' => [], 'addedWeight' => 0 }
]
]
代码中的注释应该解释最重要的部分:
function parseInput($input) {
$lines = preg_split('/(\r\n|\n)/', $input, null, PREG_SPLIT_NO_EMPTY);
$count = (int) array_shift($lines); // we don't need this item
$balances = array();
$side = array();
foreach($lines as $line) {
// get the numbers from one line in an array of numbers
$args = array_map('intval', explode(' ', $line));
$obj = new stdClass();
// first number represents the weight
$obj->weight = array_shift($args);
// all other numbers represent IDs of balances
$obj->balances = $args;
// collect this as a side, next iteration will fill other side
$side[] = $obj;
if (count($side) == 2) {
// after each two lines, add the two objects to main array
$balances[] = $side;
$side = array();
}
}
return $balances;
}
function addWeights(&$balances, $id) {
if ($id == -1) {
// There is no balance here: return 0 weight
return 0;
}
// Check that structure is not cyclic:
if (isset($balances[$id][0]->addedWeight)) {
throw new Exception("Invalid balance structure: #$id re-encountered");;
}
$total = 10; // weight of balance itself
$added = 0;
foreach($balances[$id] as &$side) {
// get the direct weight put in the balance:
$weight = $side->weight;
// add to it the total weight of any balances on this side,
// by using recursion
foreach($side->balances as $balanceId) {
$weight += addWeights($balances, $balanceId);
}
// calculate difference in left/right total weight
$added = $weight - $added;
$total += $weight;
// create new property with result
$side->addedWeight = 0;
}
// set either left or right added weight:
$balances[$id][$added > 0 ? 0 : 1]->addedWeight = abs($added);
$total += abs($added);
return $total;
}
function balance(&$balances) {
// If the only root balance was at index 0, we could just
// call addWeights($balances, 0), but it might be elsewhere
// and there might even be multiple roots:
foreach($balances as $index => $balance) {
if (!isset($balance[0]->addedWeight)) {
addWeights($balances, $index);
}
}
}
function outputString(&$balances) {
$output = '';
foreach($balances as $index => $balance) {
$output .= "$index: {$balance[0]->addedWeight} {$balance[1]->addedWeight}\n";
}
return $output;
}
它的使用方法如下:
// test data
$input =
"4
0 1
0 2
0
0 3
3
0
0
0";
// 1. transform input into structure
$balances = parseInput($input);
// 2. main algorithm
balance($balances);
// 3. output the result in desired format
echo outputString($balances);
输出是:
0: 0 14
1: 10 0
2: 0 3
3: 0 0