我正在尝试编写一种算法来查找n个数字的排序方式。例如,两个数字表示a和b可以用3种方式排序..
同样,3种数字可以13种方式排列。
我发现我可以使用动态编程解决问题。这就是我想要的是具有代表不同排序的图层。防爆。 a > b
有两层,a = b
有一层,依此类推。这样我就可以像动态编程一样将它用于以后的目的。但是我不能为它写一个递归关系。有人可以建议我怎么写那个?
答案 0 :(得分:1)
假设f(n,k)=具有k不等式(以及n-k-1相等)的可能方式的数量,因此: 假设您有n-1个数字,现在您想要添加另一个数字并计算f(n,k),那么我们有两种可能性:
1)那些(n-1)个数中存在(k-1)个不等式,并且有(k + 1)(f(n-1,k-1)个)方法来添加第n个数,所以新的不平等增加了。
2)在那些(n-1)个数中存在k个不等式,并且存在(k + 1)(f(n-1,k))个方法来添加第n个数而没有额外的不等式。
f(n,k) = (k+1)(f(n-1,k-1) + f(n-1,k))
你想要的是它们的总和(从0到n-1),Bellow代码在c#中(仅针对简单情况进行测试),实际上我们只计算了不能生成所有方式的可能方式的数量..
class EqualInequalPermutation
{
public int OrderingsNumber(int n)
{
int[][] f = new int[n+1][];
for (int i = 0; i < n+1; i++)
{
f[i] = new int[n];
for (int j = 0; j < n; j++)
f[i][j] = 0;
}
f[1][0] = 1;
int factorial = 1;
for (int i = 1; i <= n; i++)
{
f[i][0] = 1;
factorial *= i;
f[i][i - 1] = factorial;
for (int k = 1; k < n; k++)
{
f[i][k] = (k + 1) * (f[i - 1][k - 1] + f[i - 1][k]);
}
}
int answer = 0;
for (int i = 0; i < n; i++)
{
answer += f[n][i];
}
return answer;
}
}
答案 1 :(得分:1)
我发现On-Line Encyclopedia of Integer Sequences对于像这样的问题来说是一个很好的资源。您已经提供了足够的信息来获得答案。显然,对于零数的退化情况,只能进行一次排序。对于单个数字,也只存在一个订单。对于两个,你说有三个排序,三个整数有十三个。搜索1,1,3,13,弹出的第一场比赛是this one,“竞争者在比赛中排名的方式数量,允许联系的可能性。”从那里你会看到这个序列中的前20个左右的结果,以及人们对序列贡献的内容。其中列出的是Mathematica中的递归解决方案(在此重新格式化和扩展以便澄清):
f[0] = 1
f[1] = 1
f[n_] := f[n] = Sum[ Binomial[n,k] * f[n-k], {k,1,n}] (* memoizes the values *)
如果您愿意,可以使用其他语言轻松实现。
希望这会有所帮助,并且您发现OEIS将来会有用!
答案 2 :(得分:1)
//This is the C++ version of the Same Code
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin>>n;
vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));
dp[1][0] = 1;
int f = 1;
for(int i = 1; i <= n; ++i) {
dp[i][0] = 1;
f = f * i;
dp[i][i - 1] = f;
for(int j = 1; j <= n; ++j)
dp[i][j] = (j + 1) * (dp[i - 1][j - 1] + dp[i - 1][j]);
}
int ans = 0;
for(int i = 0; i < n; ++i)
ans += dp[n][i];
cout<<ans;
return 0;
}
您可以继续求模,因为答案将成倍增加。
答案 3 :(得分:0)
老实说,我认为通过动态编程解决它就像用机枪杀死蚂蚁一样。
你绝对应该使用组合学,因为它不应该那么困难。
如果不存在等式n!
(置换),那么你必须计算组合(所有相等的n元组),所以它为3
3! + 2 *(3比2)+(3比3)= 13
答案 4 :(得分:0)
以下C#程序输出订单数量和订单本身:
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Missing argument - the number of items");
return;
}
int n;
if (!int.TryParse(args[0], out n))
{
Console.WriteLine("Could not parse number of items");
return;
}
if (n < 0)
{
Console.WriteLine("Number of items must not be negative");
return;
}
var count = GetOrderings(n);
Console.WriteLine("Total: {0}", count);
}
private static int GetOrderings(int n)
{
var items = Enumerable.Range(0, n).Select(i => (char)('a' + i)).ToList();
// Produce distinct orderings of the input items
return GetOrderings(new List<char>(), items);
}
private static int GetOrderings(List<char> current, List<char> items)
{
// If we have a complete permutation in current, produce the possible arrangements of signs between them
if (items.Count == 0) return GetSigns(new List<char>(), current, 0);
var result = 0;
for (var i = 0; i < items.Count; i++)
{
// nextCurrent = current + i'th element of items
var nextCurrent = new List<char>(current) { items[i] };
// nextItems = items excluding the i'th element
var nextItems = new List<char>(items.Where((c, n) => n != i));
result += GetOrderings(nextCurrent, nextItems);
}
return result;
}
private static int GetSigns(List<char> signs, List<char> items, int n)
{
if (signs.Count >= items.Count - 1)
{
// Once we have sufficient signs, write out the items interleaved with them
var str = string.Empty;
for (var i = 0; i < items.Count; i++)
{
if (i > 0) str += signs[i - 1];
str += items[i];
}
Console.WriteLine(str);
return 1;
}
var result = GetSigns(new List<char>(signs) { '<' }, items, n + 1);
// To prevent duplicate orderings, only allow "=" between two items if they are in lexicographic order
// (i.e. allow "a = b" but not "b = a")
if (items[n] >= items[n + 1]) return result;
return result + GetSigns(new List<char>(signs) { '=' }, items, n + 1);
}
示例输出(对于n = 3):
a<b<c a<b=c a=b<c a=b=c a<c<b a=c<b b<a<c b<a=c b<c<a b=c<a c<a<b c<a=b c<b<a Total: 13
答案 5 :(得分:0)
由于我随机地忽略了这个问题,但是在搜索结果中找不到简单的python实现。为了将来参考,下面提供了python版本的简单实现。
尽管我们可以获得更全面的数学证明here。下面的代码将仅遵循@Saeed Amiri提供的公式:
f(n,k) = (k+1)(f(n-1,k-1) + f(n-1,k))
def bell_number(num: int) -> int:
dp = [[0] * num for _ in range(num)]
dp[0][0] = 1
for n in range(1, num):
for k in range(num):
dp[n][k] = (k+1) * (dp[n-1][k-1] + dp[n-1][k])
return sum(dp[-1])