Php 寻找所有可能的交换卡的方法

Php 寻找所有可能的交换卡的方法,php,algorithm,Php,Algorithm,我正在开发一个PHP应用程序,它可以找到所有可能的交换卡的方法。每个用户至少有一张卡。当用户请求一张卡时,应用程序会向他显示所有可能的方法,以交换他所请求的卡 让我们说: user 1 has card type A user 2 has card type B user 3 has card type C 让我们假设: user 1 wants card type C user 2 wants card type A user 3 wants card type B 如果用户1请求卡C

我正在开发一个PHP应用程序,它可以找到所有可能的交换卡的方法。每个用户至少有一张卡。当用户请求一张卡时,应用程序会向他显示所有可能的方法,以交换他所请求的卡

让我们说:

user 1 has card type A
user 2 has card type B 
user 3 has card type C 
让我们假设:

user 1 wants card type C
user 2 wants card type A
user 3 wants card type B
如果用户1请求卡C,唯一的解决方案是:

user 1 gives user 2 his card
user 2 gives user 3 his card
user 3 gives user 1 his card
但如果还有另外两个用户呢:

user 4 has card type B & wants card type A
user 5 has card type C & wants card type B
现在,如果用户1请求卡C,除了上面的解决方案外,还有一个解决方案:

user 1 gives user 4 his card
user 4 gives user 5 his card
user 5 gives user 1 his card

用户可以拥有或请求的卡数没有限制。到目前为止,我创建了两个SQL表。表“cards”记录每个用户ID和cardID。“requests”表跟踪每个用户ID和所需的cardID

我不会使用纯PHP来实现这一点。我更愿意创建一个MySQL表,为每个用户存储一条记录,记录该用户拥有的卡以及他想要的卡。然后,我会运行这样的程序:

$sql = "SELECT * FROM users";
$result = $this->db->query();
$users = $result->getAll(); //A list of all the users.

foreach ($users as $user)
{
   $sql = "SELECT * FROM users WHERE cardId = '$user->wantedCardId'";
   $result = $this->db->query($sql);

   if (! $result->has_rows())
   {
      echo "No other users with $user->wantedCardId were found.";
      continue;
   }

   $cardHolder = $result->row();
   echo: "User $cardHolder->id gives $user->id his card";
}
//Populate an array containing a list of all the users and their cards.

$users = array();

$user[1] = new StdClass();;
$user[1]->cardId = 2;
$user[1]->wantedId = 3;

$user[2] = new StdClass();
$user[2]->cardId = 3;
$user[2]->wantedId = 2;
// .....

foreach ($users as $userId=>$user)
{
   //Run a secondary loop through the users to find those that have the card that
   //this user wants.
   foreach ($users as $holderId=>$cardHolder)
   {
      if ($cardHolder->cardId != $user->wantedId)
         continue;
      echo "User $holderId gives $userId his card";
   }
}
如果我使用普通PHP进行此操作,我将执行以下操作:

$sql = "SELECT * FROM users";
$result = $this->db->query();
$users = $result->getAll(); //A list of all the users.

foreach ($users as $user)
{
   $sql = "SELECT * FROM users WHERE cardId = '$user->wantedCardId'";
   $result = $this->db->query($sql);

   if (! $result->has_rows())
   {
      echo "No other users with $user->wantedCardId were found.";
      continue;
   }

   $cardHolder = $result->row();
   echo: "User $cardHolder->id gives $user->id his card";
}
//Populate an array containing a list of all the users and their cards.

$users = array();

$user[1] = new StdClass();;
$user[1]->cardId = 2;
$user[1]->wantedId = 3;

$user[2] = new StdClass();
$user[2]->cardId = 3;
$user[2]->wantedId = 2;
// .....

foreach ($users as $userId=>$user)
{
   //Run a secondary loop through the users to find those that have the card that
   //this user wants.
   foreach ($users as $holderId=>$cardHolder)
   {
      if ($cardHolder->cardId != $user->wantedId)
         continue;
      echo "User $holderId gives $userId his card";
   }
}

您可以用有向图来表示问题。用户是图形的顶点,边表示用户X拥有用户Y想要的卡。您不需要代表碰巧拥有所需卡片的用户

该问题的解决方案是一组边,确保每个顶点只有一条输出边,而只有一条输入边

编辑

我忽略了一个事实,即一个用户可能有多张卡。我想他可能还需要几张牌。在这种情况下,我将每个用户表示为一个顶点,每个X都需要一张Y作为边的卡,即使X等于Y。然后问题的解决方案是一组边,使每个人都有他们想要的卡,并且不允许任何用户多次给同一张卡

我会给每张卡分配一个数字,并记录每个用户在乞讨时每个数字有多少张卡,以及用户有多少个相同数字的输出边来检查。如果一个用户从不“想要”他“拥有”的类型来计算它可以完成的方式,组合数学就足够了,不需要算法。如果要“显示”交换发生的方式,则:

要可视化问题,请按以下方式排列类型:

        TYPE A       ...........................     TYPE N

    |          |                                   |          |   
    |          |                                   |          | 
    | USER 2   |                                   |          | 
    | USER 1   |                                   |          | 
    | USER 1   |                                   +..........+
    +----------+                              
        HAS


       WANTS
    +----------+ 
    | USER 3   |
    | USER 4   |
    | USER 5   |
    |          |                
在我们的示例中,用户1有两张A型卡,用户2有一张,用户3、4和5各想要一张A型卡

让我们在这一刻思考一下A型卡片

您需要成对交换卡片,如顺序卡片:

 {{usr 1,usr3},{usr1, usr 4}, {usr2,usr5}}
如果每个用户都满意,那么会有和询问者相同的所有者

现在,要形成成对,您知道必须在不重新定位的情况下从每个集合中拾取一个元素。因为可能会有重复(用户想要或拥有一种类型的多张卡),所以您也必须考虑到这一点。这是为了计算每种类型应“处理”的方式。组合数学就足够了

要形成成对,您可以:

1) 构造每个集合的所有不同排列:

    {2, 1, 1}  {1, 2, 1}  {1, 1, 2}  # == 3!/2!
    {3, 4, 5}  {5, 3, 4}  {4, 5, 3} {4, 3, 5} {5, 4, 3} {3, 5, 4} # == 3!
2) 在我们的示例中,对于每一对排列,都有一个不同的结果集3 x 6=18。

对所有卡类型执行相同操作


最后,对于每种卡片类型,您有N个可能的结果集。为了获得交换所有卡片的所有可能方式,您必须为每种类型组合所有可能方式

这与PHP无关,删除PHP标记以便更多用户查看它。是否会限制您拥有的卡和用户数量?这可能是一个很难解决的问题。您可以将任何置换分解为一系列循环,这是一个开始:您将不得不进行某种约束,否则您将有无限多的解决方案(例如1,2保持交换卡)。