当前位置: 首页 > 知识库问答 >
问题:

一种基于项目权重的高效多列表合并方法

牛凌
2023-03-14

我正在写一个国际象棋引擎,我需要一种有效的方法,将多个列表合并成一个按最小值排序的单数列表。

每个列表本质上是一组棋子,它们已经按照完美的攻击顺序排列。例如,我在a2上有一个白色的皇后,在b3上有一个白色的主教,在f1上有一个白色的车,在F2上有一个白色的车。现在假设我在f7上有一个黑色棋子,那么所有四个白色棋子从两个不同的离散方向汇聚在f7广场上--东北(皇后&毕晓普)和北方(鲁克斯)。

一些代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SO_22015528
{
  public enum eRayDirection
  {
    North,
    NorthEast,
    East,
    SouthEast,
    South,
    SouthWest,
    West,
    NorthWest
  }

  public enum ePieceType
  {
    Empty = 0,
    Pawn = 1,
    Knight = 2,
    Bishop = 3,
    Rook = 4,
    Queen = 5,
    King = 6
  }

  public struct BoardPosition : IComparable<BoardPosition>
  {
    public int File;
    public int Rank;
    public int Square;

    public BoardPosition( int square )
    {
      Square = square;
      File = square % 7;
      Rank = 8 - ( square >> 3 );
    }

    public static Boolean operator >( BoardPosition b1, BoardPosition b2 )
    {
      return ( b1.Rank > b2.Rank ) || ( b1.Rank == b2.Rank && b1.File < b2.File );
    }

    public static Boolean operator <( BoardPosition b1, BoardPosition b2 )
    {
      return ( b1.Rank < b2.Rank ) || ( b1.Rank == b2.Rank && b1.File > b2.File );
    }

    public int CompareTo( BoardPosition obj )
    {
      if ( this < obj ) return 1;
      else if ( this > obj ) return -1;
      else return 0;
    }
  }

  public class ChessPiece
  {
    public int Value { get; set; }
    public ePieceType Type { get; set; }
    public int Square { get; set; }
    public BoardPosition XY
    {
      get
      {
        return new BoardPosition( this.Square );
      }
    }
    public ChessPiece( ePieceType type, int value, int square )
    {
      Value = value;
      Type = type;
      Square = square;
    }
  }

  public class Constraint
  {
    public ChessPiece Piece { get; set; }
    public eRayDirection Ray { get; set; }
    public Constraint( ChessPiece piece, eRayDirection ray )
    {
      Piece = piece;
      Ray = ray;
    }
    public override string ToString()
    {
      return String.Format( "{0} {1} {2}", Piece.Square, Piece.Type, Ray );
    }
  }

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SO_22015528
{
  class Program
  {
    static void Main( string[] args )
    {
      // test code
      ChessPiece a2 = new ChessPiece( ePieceType.Queen, 900, 48 );
      ChessPiece b3 = new ChessPiece( ePieceType.Bishop, 375, 41 );
      ChessPiece f1 = new ChessPiece( ePieceType.Rook, 500, 61 );
      ChessPiece f2 = new ChessPiece( ePieceType.Rook, 500, 53 );

      // This just simulates pieces that attack on the f7 square.
      List<Constraint> f7 = new List<Constraint>();
      f7.Add( new Constraint( b3, eRayDirection.NorthEast ) );
      f7.Add( new Constraint( a2, eRayDirection.NorthEast ) );
      f7.Add( new Constraint( f1, eRayDirection.North ) );
      f7.Add( new Constraint( f2, eRayDirection.North ) );

      // Get all positive ray directions ( use to simplify LINQ orderby )
      List<eRayDirection> positiveRayDirections = new List<eRayDirection>();
      positiveRayDirections.Add( eRayDirection.North );
      positiveRayDirections.Add( eRayDirection.NorthEast );
      positiveRayDirections.Add( eRayDirection.NorthWest );
      positiveRayDirections.Add( eRayDirection.West );

      var groups = f7
        .GroupBy( g => g.Ray )
        .Select( a =>
        new
        {
          Key = a.Key,
          Results = positiveRayDirections.Contains( a.Key ) ? a.OrderBy( x => x.Piece.XY ).ToList() : a.OrderByDescending( x => x.Piece.XY ).ToList()
        } ).ToList();

              // The groups object returns two discrete groups here; 
              // NorthEast containing 2 entries (Bishop & Queen) and North 
              // also containing to entries (Rook x 2).
      List<Constraint> attackOrder = new List<Constraint>();

      List<Int32> groupIndicies = new List<Int32>( groups.Count() );
      for ( int n = 0; n < groups.Count(); n++ )
        groupIndicies.Add( 0 );

      while ( true )
      {
        Int32 value = Int32.MaxValue;
        Int32 groupIndex = -1;

        for ( int n = 0; n < groups.Count(); n++ )
        {
          var g = groups[ n ];
          int gIndex = groupIndicies[ n ];

          if ( gIndex < g.Results.Count && g.Results[ gIndex ].Piece.Value < value )
          {
            value = g.Results[ gIndex ].Piece.Value;
            groupIndex = n;
          }
        }

        if ( groupIndex < 0 )
          break;

        attackOrder.Add( groups[ groupIndex ].Results[ groupIndicies[ groupIndex ] ] );

        groupIndicies[ groupIndex ]++;

      }

              foreach ( var ao in attackOrder )
                  Console.WriteLine( ao.ToString() );

      Console.ReadKey();
    }
  }
}

我不认为最后一点是非常有效的,如果有人能找到一个更简单的方法,我会很感激。

共有1个答案

鲁宏爽
2023-03-14

使用quicksort对每个列表分别排序,然后通过insert排序到最终列表中。

Order the lists individually.
Create the empty Final list.

do
{
   consider the first item in each of the sorted lists and find the highest ranking candidate.
   remove the item from its sorted list and add it to the final list.
} 
until all of the sorted lists are empty.
 类似资料:
  • 在读取行并将条目对象添加到列表中时(这需要很长时间),程序以OutOfMemoryException“Java堆”终止。 所以我的方法似乎对内存(和运行时)太难了。 有什么更好的方法吗?

  • 我有一个如下所示的dataframe,但我真正的dataframe有数百万行 我想查找每24小时执行测试的次数(使用测试列标识

  • 这不是经典的“合并两个排序”列表问题,这在线性时间内是相当微不足道的。 我想做的是合并两个对的列表,它们已经按排序,其中两个列表中都有具有相同的对象:这些对象应该合并(添加)它们的

  • 我有三个数据帧。它们都有一个公共列,我需要基于公共列合并它们,而不丢失任何数据 输入 预期输出

  • 问题内容: 我使用以下方式列出了重复项: 现在,如何删除除一条消息以外的所有消息(我正在尝试删除重复项,以便可以在上应用唯一索引)。 问题答案: 使用和分配行号,以便删除重复对中除一个以外的所有行。

  • a = [i for i in range(1, 8000)] 假如有个这样的列表, 我需要把里面的所有值组合 然后求 组合的总和与100差的最小值。 例如 1和2组合 1+2 =3 与100 差 3-100 == -97 , 1和3组合 1+3-100 = -96 , 1和4组合,1+4-100=-95..... 1+99-100=0 ....依次类推, 1+2+3+4+5+6...+7999-