0

该数据库包含一个团队列表,每个团队都按位置分隔(西队、东队等)。有两种事实可以描述这一点。团队(团队编号,损失)和区域(团队编号,区域)。例如:

team(1, 10).
team(2, 11).
team(3, 12).
team(4, 13).

region(1, east).
region(2, west).
region(3, east).
region(4, southeast).

注意:球队名单并不总是按照损失最小到最大损失的顺序排列。

我正在尝试将一组团队配对在一起,以便将损失最高的团队与损失最少的团队配对,然后将损失第二高的团队与损失第二少的团队配对,等等。规则是,在同一区域内配对团队是一个优先事项。在上面的示例中,第 3 队和第 1 队将被配对,因为他们都是东部球队。现在,剩下的队伍是 2 队和 4 队。但由于他们所在的地区没有其他球队,所以 2 队和 4 队相互匹配。

现在,我正在考虑我可以编写什么函数来配对团队。我已经编写了一个函数来将一个区域内的所有不同团队分组到一个相应的列表中。我还编写了一个函数来获取最小值和最大值(最高和最低损失)。

我如何编写一个函数来配对同一区域内的所有团队,然后制作一个新列表,将所有剩余的团队粘贴在该列表中?

4

2 回答 2

2

我还编写了一个函数来获取最小值和最大值(最高和最低损失)。

Prolog 和其他声明性语言在一些令人惊讶的方面不同于过程语言,其中之一是经常做一些工作以期望从某种循环结构中重用它并不是完全正确的方法。这在 SQL 中更为明显,您应该始终根据集合进行处理,但它也适用于 Prolog,我们拥有的少数显式循环结构并未大量使用。

在程序环境中匹配低分和高分球队的问题最好通过这样的过程来解决:

def match(teams):
  while we have teams:
    remove the lowest scoring team from teams
    remove the highest scoring team from teams
    save this pair
  return the list of pairs

使此功能更具功能性的一种天真的方法是使用递归:

def match(teams):
  if teams is empty: return empty list
  otherwise:
    remove the lowest scoring team
    remove the highest scoring team
    return this pair appended to match(teams without these two items)

您实际上可以毫不费力地将其转换为外观合理的 Prolog:

match([], []).
match(Teams, [Lowest-Highest|Pairs]) :-
  lowest(Teams, Lowest),
  highest(Teams, Highest),
  select(Lowest, Teams, TeamsWithoutLowest),
  select(Highest, TeamsWithoutLowest, RemainingTeams),
  match(RemainingTeams, Pairs).

这不太可能是有效的,因为在 内部有大量重复的列表扫描和大量的列表重建select/3,但它可能更具声明性。

另一种方法是对团队列表进行排序,然后将其折叠回自身以获得最低和最高配对。视觉上:

[1, 2, 3, 4, 5, 6]
[1, 2, 3],  [4, 5, 6]
[1, 2, 3],  [6, 5, 4]

[1,     2,     3]
[6,     5,     4]
-------------------
[1-6], [2-5], [3-4]

我们可以直接在 Prolog 中执行此操作,但首先我们需要一种方法来配对两个列表:

pair_off([], _, []).
pair_off([L|Ls], [R|Rs], [L-R|Rest]) :- pair_off(Ls, Rs, Rest).

然后算法像这样进入 Prolog:

match_lowest_highest(SortedList, Pairs) :-
  length(SortedList, N2),
  N is N2 div 2,
  length(TopHalf, N),
  append(TopHalf, BottomHalf, SortedList),
  reverse(BottomHalf, BottomHalfFlipped),
  pair_off(TopHalf, BottomHalfFlipped, Pairs).

这仍然不是非常有效,但reverse/2内置可能正在使用差异列表,所以它不应该太贵;通过使用append/3已经物化的未知数列表,我们节省了一堆临时列表结构,这些结构将被丢弃。所以我不认为这会非常低效,但我相信还有其他方法可以做到这一点,效率更高。

于 2013-03-04T04:13:13.063 回答
1

好的,我已经试了一下。我认为 all_teams_paired/2 将提供您所描述的所有配对团队的列表,以及剩余团队(如果有奇数个团队)。

% list of all regions
regions(Regions) :- 
    findall(Region, region(_, Region), UnsortedRegions),
    sort(UnsortedRegions, Regions).

% list of all teams in a region
teams_in_region(Region, Teams) :- findall(Team, (team(Team, _), region(Team, Region)), Teams).

% bottom team in a list
bottom_team(TeamList, BottomTeam) :-
    member(BottomTeam, TeamList),
    findall(Losses, (team(Team, Losses), member(Team, TeamList)), AllLosses),
    team(BottomTeam, Losses),
    min_member(Losses, AllLosses).

% top team in a list
top_team(TeamList, TopTeam) :-
    member(TopTeam, TeamList),
    findall(Losses, (member(Team, TeamList), team(Team, Losses)), AllLosses),
    team(TopTeam, Losses),
    max_member(Losses, AllLosses).

% teams are paired with the top loser playing the bottom loser and there can be a leftover
%  if there is an odd number of teams
paired_teams([], [], []).
paired_teams([LonelyTeam], [], [LonelyTeam]).
paired_teams(TeamList, PairedTeams, UnpairedTeam) :-
    top_team(TeamList, TopTeam),
    bottom_team(TeamList, BottomTeam),
    TopTeam \= BottomTeam,
    subtract(TeamList, [TopTeam, BottomTeam], RemainingTeams),
    paired_teams(RemainingTeams, RemainingPairedTeams, UnpairedTeam),
    append([TopTeam-BottomTeam], RemainingPairedTeams, PairedTeams).

% a list of regions has an associated list of paired teams and leftover teams
region_paired_teams([], [], []).
region_paired_teams(Regions, PairedTeams, UnpairedTeams) :-
    Regions = [Region|RemainingRegions],
    teams_in_region(Region, TeamList),
    paired_teams(TeamList, RegionPairedTeams, RegionUnpairedTeam),
    region_paired_teams(RemainingRegions, RemainingPairedTeams, RemainingUnpairedTeams),
    append(RegionPairedTeams, RemainingPairedTeams, PairedTeams),
    append(RegionUnpairedTeam, RemainingUnpairedTeams, UnpairedTeams).

% a list of all teams paired with priority given to region and a leftover team (if any)
all_teams_paired(TeamsPaired, Leftover) :-
    regions(Regions),
    region_paired_teams(Regions, RegionPairedTeams, UnpairedTeams),
    paired_teams(UnpairedTeams, NonRegionPairedTeams, Leftover),
    append(RegionPairedTeams, NonRegionPairedTeams, TeamsPaired).

我是否正确理解了您的要求?

于 2013-03-02T11:01:29.220 回答