配对团队

时间:2013-03-02 06:05:17

标签: prolog

数据库包含一个团队列表,每个团队按位置分隔(West团队,East团队等)。有两种类型的事实可以描述这一点。团队(TeamNumber,损失)和地区(TeamNumber,地区)。例如:

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队相互匹配。

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

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

2 个答案:

答案 0 :(得分: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已经实现的未知数列表,我们可以保存一堆临时列表构造,这些构造只会被丢弃。所以我不认为这会非常低效,但我确信还有其他方法可以做得更有效率。

答案 1 :(得分: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).

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