我正在开发一个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”跟踪每个userID和cardID。表“请求”跟踪每个用户ID和所需的cardID。
答案 0 :(得分:1)
我不会为此使用纯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";
}
如果我使用普通PHP来做这件事,我会做这样的事情:
//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";
}
}
答案 1 :(得分:1)
您可以使用有向图表示问题。用户将是图表的顶点,并且边缘表示用户X具有用户Y想要的卡的事实。您无需代表碰巧拥有所需卡片的用户。
问题的解决方案是边缘集合,确保每个顶点只有一个输出边缘,并且只有一个输入边缘。
修改强>
我错过了一个用户可能拥有多张卡的事实。我想他可能还需要几张牌。在这种情况下,我会将每个用户表示为一个顶点,并且每个 X都需要一张Y具有作为边缘的卡,即使X等于Y.那么问题的解决方案就是边缘集合这使得每个人都拥有他们想要的卡片,并且不允许任何用户多次提供同一张卡片。
我会通过为每张卡分配一个号码来检查,并跟踪每个用户在乞讨时每个号码的卡数,以及用户拥有相同数量的输出边缘数。
答案 2 :(得分:1)
如果一个用户从不“想要”一种类型,他“有”计算它可以完成的方式组合就足够了,不需要算法。如果您想“显示”交换的方式,那么:
为了可视化问题,请按以下方式排列类型:
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个可能的结果集。为了获得所有可能的方式来交换所有卡片,你必须为每种类型组合所有可能的方式......