【发布时间】:2013-04-15 23:44:08
【问题描述】:
如果您在阅读问题后能想出一个更好的标题,请随时更改。
所以,作为输入,我有一个整数,它是 2 到 20 之间的偶数。我们称这个整数为$teams。我需要做的是在遵守以下规则的同时生成一个$teams x $teams 大小的介于 1 和 $teams-1(含)之间的数字矩阵:
- 对角线(从左上角到右下角)的值为 -1。
- 同一数字不能在同一列或同一行中出现多次。
- 如果一个数字出现在 N 列,那么 in 可能不会出现在 N 行。例如,如果它出现在第 2 列,它可能不会出现在第 2 行,等等。
请注意,我们只查看对角线上方的部分。它下面的部分只是一个反映(每个数字是它的反映 + $teams - 1),与这个问题无关。
前两个条件相当容易完成,但第三个条件让我很生气。我不知道如何实现它,特别是因为$teams 数字可能是 2 到 20 之间的任何偶数。下面给出了为条件 1 和 2 提供正确输出的代码。有人可以帮我解决第 3 个条件吗?
$teams = 6; //example value - should work for any even Int between 2 and 20
$games = array(); //2D array tracking which week teams will be playing
//do the work
for( $i=1; $i<=$teams; $i++ ) {
$games[$i] = array();
for( $j=1; $j<=$teams; $j++ ) {
$games[$i][$j] = getWeek($i, $j, $teams);
}
}
//show output
echo '<pre>';
$max=0;
foreach($games as $key => $row) {
foreach($row as $k => $col) {
printf('%4d', is_null($col) ? -2 : $col);
if($col > $max){
$max=$col;
}
}
echo "\n";
}
printf("%d teams in %d weeks, %.2f weeks per team\n", $teams, $max, $max/$teams);
echo '</pre>';
function getWeek($home, $away, $num_teams) {
if($home == $away){
return -1;
}
$week = $home+$away-2;
if($week >= $num_teams){
$week = $week-$num_teams+1;
}
if($home>$away){
$week += $num_teams-1;
}
return $week;
}
当前代码(对于 $teams=6)给出以下输出:
-1 1 2 3 4 5
6 -1 3 4 5 1
7 8 -1 5 1 2
8 9 10 -1 2 3
9 10 6 7 -1 4
10 6 7 8 9 -1
6 teams in 10 weeks, 1.67 weeks per team
如您所见,数字 1 出现在第 2 列和第 2 行,数字 4 出现在第 5 列和第 5 行等,这违反了规则 3。
【问题讨论】:
-
也许有更简单的解决方案,但你可以看看回溯:en.wikipedia.org/wiki/Backtracking
-
谢谢,但我宁愿先探索更简单的潜在解决方案。回溯看起来肯定可以解决它,但需要付出很多努力,而且在迭代次数方面似乎效率不高(尽管考虑到 $teams 的数量很少,这并不是什么大问题)。
-
我想到的一件事是当您说“数字出现在第 n 列”时,指的是第一行的
nth collumn。好吧,你知道在第一行你有从-1到n-1的数字。当您生成行号x的数字时,您可以轻松跳过$games[1][x]中的数字。希望有所帮助;-) -
@Havelock 我会试试的,谢谢。我怀疑最后一行会有错误的条目,因为那时别无选择。
-
@robert 我想说先尝试在一张纸上得到一个正确的解决方案,然后看看你是否可以在行和列中的数字之间提取一些依赖关系,这会导致你正确的算法。