我怎样才能遍历n张扑克牌的每种可能的组合

发布于 2024-10-18 16:20:09 字数 38 浏览 1 评论 0 原文

如何循环遍历一副标准 52 张牌中的 n 张扑克牌的所有组合?

How can I loop through all combinations of n playing cards in a standard deck of 52 cards?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

多彩岁月 2024-10-25 16:20:09

您需要一组 N 项中的 n 项的所有组合(在您的情况下,N == 52,但我会保留回答通用)。

每个组合都可以表示为项目索引数组 size_t item[n],这样:

  • 0 <= item[i] < N
  • item[i] < item[i+1],这样每个组合都是一个唯一的子集。

item[i] = i 开始。然后迭代到下一个组合:

  • 如果最终索引可以递增(即item[n-1] < N-1),则执行此操作。
  • 否则,向后工作,直到找到一个可以递增的索引,并且仍然为所有后续索引留出空间(即 item[ni] )。增加该值,然后将所有以下索引重置为尽可能小的值。
  • 如果您找不到任何可以增加的索引(即 item[0] == Nn),那么您就完成了。

在代码中,它可能看起来像这样(未经测试):

void first_combination(size_t item[], size_t n)
{
    for (size_t i = 0; i < n; ++i) {
        item[i] = i;
    }
}

bool next_combination(size_t item[], size_t n, size_t N)
{
    for (size_t i = 1; i <= n; ++i) {
        if (item[n-i] < N-i) {
            ++item[n-i];
            for (size_t j = n-i+1; j < n; ++j) {
                item[j] = item[j-1] + 1;
            }
            return true;
        }
    }
    return false;
}

让它更通用,并且看起来更像 std::next_permutation 可能会更好,但这就是一般想法。

You need all combinations of n items from a set of N items (in your case, N == 52, but I'll keep the answer generic).

Each combination can be represented as an array of item indexes, size_t item[n], such that:

  • 0 <= item[i] < N
  • item[i] < item[i+1], so that each combination is a unique subset.

Start with item[i] = i. Then to iterate to the next combination:

  • If the final index can be incremented (i.e. item[n-1] < N-1), then do that.
  • Otherwise, work backwards until you find an index that can be incremented, and still leave room for all the following indexes (i.e. item[n-i] < N-i). Increment that, then reset all the following indexes to the smallest possible values.
  • If you can't find any index that you can increment (i.e. item[0] == N-n), then you're done.

In code, it might look something vaguely like this (untested):

void first_combination(size_t item[], size_t n)
{
    for (size_t i = 0; i < n; ++i) {
        item[i] = i;
    }
}

bool next_combination(size_t item[], size_t n, size_t N)
{
    for (size_t i = 1; i <= n; ++i) {
        if (item[n-i] < N-i) {
            ++item[n-i];
            for (size_t j = n-i+1; j < n; ++j) {
                item[j] = item[j-1] + 1;
            }
            return true;
        }
    }
    return false;
}

It might be nice to make it more generic, and to look more like std::next_permutation, but that's the general idea.

口干舌燥 2024-10-25 16:20:09

该组合迭代器类源自此处发布的先前答案。

我做了一些基准测试,它比您之前使用的任何 next_combination() 函数至少快 3 倍。

我在 MetaTrader mql4 中编写了代码来测试外汇三角套利交易。我认为你可以轻松地将其移植到 Java 或 C++。

class CombinationsIterator
{
private:
	int input_array[];
	int index_array[];
	int m_indices;      // K
	int m_elements;     // N

public:
	CombinationsIterator(int &src_data[], int k)
	{
		m_indices = k;
		m_elements = ArraySize(src_data);
		ArrayCopy(input_array, src_data);
		ArrayResize(index_array, m_indices);

		// create initial combination (0..k-1)
		for (int i = 0; i < m_indices; i++)
		{
			index_array[i] = i;
		}
	}

	// https://stackoverflow.com/questions/5076695
	// bool next_combination(int &item[], int k, int N)
	bool advance()
	{
		int N = m_elements;
		for (int i = m_indices - 1; i >= 0; --i)
		{
			if (index_array[i] < --N)
			{
				++index_array[i];
				for (int j = i + 1; j < m_indices; ++j)
				{
					index_array[j] = index_array[j - 1] + 1;
				}
				return true;
			}
		}
		return false;
	}

	void get(int &items[])
	{
		// fill items[] from input array
		for (int i = 0; i < m_indices; i++)
		{
			items[i] = input_array[index_array[i]];
		}
	}
};

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
// driver program to test above class

#define N 5
#define K 3

void OnStart()
{
	int x[N] = {1, 2, 3, 4, 5};

	CombinationsIterator comboIt(x, K);

	int items[K];

	do
	{
		comboIt.get(items);

		printf("%s", ArrayToString(items));

	} while (comboIt.advance());

}

输出:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5

This combinations iterator class is derived from the previous answers posted here.

I did some benchmarks and it is a least 3x faster than any next_combination() function you would have used before.

I wrote the code in MetaTrader mql4 to do testing of triangular arbitrage trading in forex. I think you can port it easily to Java or C++.

class CombinationsIterator
{
private:
	int input_array[];
	int index_array[];
	int m_indices;      // K
	int m_elements;     // N

public:
	CombinationsIterator(int &src_data[], int k)
	{
		m_indices = k;
		m_elements = ArraySize(src_data);
		ArrayCopy(input_array, src_data);
		ArrayResize(index_array, m_indices);

		// create initial combination (0..k-1)
		for (int i = 0; i < m_indices; i++)
		{
			index_array[i] = i;
		}
	}

	// https://stackoverflow.com/questions/5076695
	// bool next_combination(int &item[], int k, int N)
	bool advance()
	{
		int N = m_elements;
		for (int i = m_indices - 1; i >= 0; --i)
		{
			if (index_array[i] < --N)
			{
				++index_array[i];
				for (int j = i + 1; j < m_indices; ++j)
				{
					index_array[j] = index_array[j - 1] + 1;
				}
				return true;
			}
		}
		return false;
	}

	void get(int &items[])
	{
		// fill items[] from input array
		for (int i = 0; i < m_indices; i++)
		{
			items[i] = input_array[index_array[i]];
		}
	}
};

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
// driver program to test above class

#define N 5
#define K 3

void OnStart()
{
	int x[N] = {1, 2, 3, 4, 5};

	CombinationsIterator comboIt(x, K);

	int items[K];

	do
	{
		comboIt.get(items);

		printf("%s", ArrayToString(items));

	} while (comboIt.advance());

}

Output:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5

ゝ杯具 2024-10-25 16:20:09
#include <iostream>
#include <vector>
using namespace std;

class CombinationsIndexArray {
    vector<int> index_array;
    int last_index;
    public:
    CombinationsIndexArray(int number_of_things_to_choose_from, int number_of_things_to_choose_in_one_combination) {
        last_index = number_of_things_to_choose_from - 1;
        for (int i = 0; i < number_of_things_to_choose_in_one_combination; i++) {
            index_array.push_back(i);
        }
    }
    int operator[](int i) {
        return index_array[i];
    }
    int size() {
        return index_array.size();
    }
    bool advance() {

        int i = index_array.size() - 1;
        if (index_array[i] < last_index) {
            index_array[i]++;
            return true;
        } else {
            while (i > 0 && index_array[i-1] == index_array[i]-1) {
                i--;
            }
            if (i == 0) {
                return false;
            } else {
                index_array[i-1]++;
                while (i < index_array.size()) {
                    index_array[i] = index_array[i-1]+1;
                    i++;
                }
                return true;
            }
        }
    }
};

int main() {

    vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);
    a.push_back(5);
    int k = 3;
    CombinationsIndexArray combos(a.size(), k);
    do  {
        for (int i = 0; i < combos.size(); i++) {
            cout << a[combos[i]] << " ";
        }
        cout << "\n";
    } while (combos.advance());

    return 0;
}

输出:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5
#include <iostream>
#include <vector>
using namespace std;

class CombinationsIndexArray {
    vector<int> index_array;
    int last_index;
    public:
    CombinationsIndexArray(int number_of_things_to_choose_from, int number_of_things_to_choose_in_one_combination) {
        last_index = number_of_things_to_choose_from - 1;
        for (int i = 0; i < number_of_things_to_choose_in_one_combination; i++) {
            index_array.push_back(i);
        }
    }
    int operator[](int i) {
        return index_array[i];
    }
    int size() {
        return index_array.size();
    }
    bool advance() {

        int i = index_array.size() - 1;
        if (index_array[i] < last_index) {
            index_array[i]++;
            return true;
        } else {
            while (i > 0 && index_array[i-1] == index_array[i]-1) {
                i--;
            }
            if (i == 0) {
                return false;
            } else {
                index_array[i-1]++;
                while (i < index_array.size()) {
                    index_array[i] = index_array[i-1]+1;
                    i++;
                }
                return true;
            }
        }
    }
};

int main() {

    vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);
    a.push_back(5);
    int k = 3;
    CombinationsIndexArray combos(a.size(), k);
    do  {
        for (int i = 0; i < combos.size(); i++) {
            cout << a[combos[i]] << " ";
        }
        cout << "\n";
    } while (combos.advance());

    return 0;
}

Output:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5
救赎№ 2024-10-25 16:20:09

我发现这个问题本质上与电源设置问题相同。请参阅编写 powerset 代码时遇到的问题以获得优雅的解决方案。

I see this problem is essentially the same as the power set problem. Please see Problems with writing powerset code to get an elegant solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文