高分求助,有没有部分全排列的算法

6048475 2010-03-01 12:21:42
最近碰到一个问题,如下:给定n个元素,这n个元素分为了m组,每组元素个数不等,
基本上形如a=((a1,a2,..ai),(b1,b2,..bi),..(x1,x2,..xi))的形式,各个分组的顺序是确定了的,现在需要求出在分组顺序确定情况下的a的所有排列,也就是将组内作全排列,然后做笛卡尔积,最后将这n个元素的字符串排列返回。

该问题较为直观的想法是使用现有的全排列算法对各个分组分别排列,然后再组装成最后的结果,但是发现可能效率和空间复杂度会有问题,有没有比较成型的简单算法,也就是不返回各个分组的全排列,而是直接返回最终的排列?本人不是数学出身,也不知道这是否是个典型问题。
...全文
260 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
绿色夹克衫 2010-03-03
  • 打赏
  • 举报
回复
非递归能比递归快多少?其实非常有限,递归本身并不慢,尤其是这种递归深度不高的(应该不超过200级)。
慢的原因主要在于组合的数量比较庞大。

btw,我给的代码是c#的,而且没有用.net本身的类库,转c很简单。

引用 10 楼 6048475 的回复:
递归版本其实我已经实现了,但是这段代码可能会非常影响性能,所以还是希望能快一些,最好用非递归的方法。
绿色夹克衫 2010-03-03
  • 打赏
  • 举报
回复
一个简单的递归版本,DFS做的,好处在于节省内存

using System;

namespace random
{
class Program
{
static char[][] Items;

static void Main(string[] args)
{
Items = new char[][] { new char[] { '1', '2', '3' }, new char[] { 'a', 'b', 'c' } };
Solve(0, 0);
Console.ReadKey();
}

static void Solve(int currentIndex, int currentArrayIndex)
{
if (currentArrayIndex < Items.GetLength(0))
{
if (currentIndex == Items[currentArrayIndex].Length)
Solve(0, currentArrayIndex + 1);
}
else
{
foreach (char[] array in Items)
Console.Write(new string(array));
Console.WriteLine();
return;
}

for (int i = currentIndex; i < Items[currentArrayIndex].Length; i++)
{
SwapItem(Items[currentArrayIndex], currentIndex, i);
Solve(currentIndex + 1, currentArrayIndex);
SwapItem(Items[currentArrayIndex], currentIndex, i);
}
}

static void SwapItem(char[] array, int indexA, int indexB)
{
char tItem = array[indexA];
array[indexA] = array[indexB];
array[indexB] = tItem;
}
}
}
6048475 2010-03-03
  • 打赏
  • 举报
回复
大家不要光说不练,能不能贴一点代码上来呢,谢啦,呵呵
6048475 2010-03-03
  • 打赏
  • 举报
回复
非递归实现还希望空间复杂度不会太高,另外希望能用C++实现,不知道加上如此多的限制条件之后是否还很简单?
6048475 2010-03-03
  • 打赏
  • 举报
回复
递归版本其实我已经实现了,但是这段代码可能会非常影响性能,所以还是希望能快一些,最好用非递归的方法。
wobelisk 2010-03-03
  • 打赏
  • 举报
回复
can be solved without recursion.
The key is to design a function to get the next permutation based on current one. Not hard to do this.
6048475 2010-03-02
  • 打赏
  • 举报
回复
不重复,但是比较注重性能,最好不用递归
6048475 2010-03-02
  • 打赏
  • 举报
回复
看来关注算法的不多阿
绿色夹克衫 2010-03-02
  • 打赏
  • 举报
回复
问题比较简单,需要考虑有重复的情况么?
6048475 2010-03-01
  • 打赏
  • 举报
回复
可能大家没弄明白我什么意思,举个例子吧:a=((a,b,c),(1,2,3)),这里共分了两个组,如果是a,b,c,1,2,3的全排列,应该有6!个,但是我们这里限制了第一个分组在第二个分组的前面,最终的结果是3!X3!=36个,它们是:
abc123
acb123
...
cba123
abc132
acb132
...
cba132
...
...
cba321
简单说来,就是将abc的全排列和123的全排列组成一个2元组,这不同的2元组一共有36个,都是abc字母在前,123数字在后的形式。最直观的算法就是调用两次全排列函数,分别对abc和123做全排列,然后将返回的两组全排列再分别组合起来,但是这样空间复杂度过高,需要在内存中保存两个组的全排列,有没有算法将全排列和2元组的形成结合起来?
quxiuer 2010-03-01
  • 打赏
  • 举报
回复
C# code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication32
{
class Program
{
static List<string> list = new List<string>();
static int s = 0;
static void Main(string[] args)
{
string strs = "12345";
Compute(strs, "");

for (int i = 0; i < list.Count; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine(s);
Console.Read();
}

/// <summary>
/// 数学排列
/// </summary>
/// <param name="num"></param>
/// <param name="curnum"></param>
public static void Compute( string num,string curnum)
{
for (int i = 0; i < num.Length; i++)
{
curnum+= num[i].ToString();
if (num.Length == 1)
{
list.Add(curnum);
s++;
}
else
{
string temp=num.Replace(num[i].ToString(),"");
Compute(temp,curnum);
curnum= curnum.Remove(curnum.Length - 1, 1);
}
}
}
}
}
小李子 2010-03-01
  • 打赏
  • 举报
回复
全排列后需要怎么做笛卡尔积?

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧