C#中的置换算法

时间:2012-02-06 22:25:20

标签: c# algorithm permutation combinatorics

我正在努力学习我需要编写的算法。我正在使用C#。

说我有一个List<Bag>我有一个List<Lunch>。 我需要编写一个算法,列出所有行李中所有午餐的排列。

例如,假设有3个午餐和2个袋子:

// Permutation 1
Bag 1, Lunch 1
Bag 2, Lunch 1

// Permutation 2
Bag 1, Lunch 1
Bag 2, Lunch 2

// Permutation 3
Bag 1, Lunch 1
Bag 2, Lunch 3

// Permutation 4
Bag 1, Lunch 2
Bag 2, Lunch 1

// Permutation 5
Bag 1, Lunch 2
Bag 2, Lunch 2

// Permutation 6
Bag 1, Lunch 2
Bag 2, Lunch 3

// Permutation 7
Bag 1, Lunch 3
Bag 2, Lunch 1

// Permutation 8
Bag 1, Lunch 3
Bag 2, Lunch 2

// Permutation 9
Bag 1, Lunch 3
Bag 2, Lunch 3

两个排列Bag 1 Lunch 1 and Bag 2 Lunch 2Bag 1 Lunch 2 and Bag 2 Lunch 1是不同的,因为行李具有不同的容量,因此它们都需要被枚举。

行李和午餐的数量可以是任意数量。

我创建了一个名为BagLunch的类,其中包含一个包和午餐对。我上面给出的示例列表将存储在List<BagLunch>

谢谢。

4 个答案:

答案 0 :(得分:4)

在LINQ中使用交叉连接:

var qry = from bag in bags
          from lunch in lunches
          select new BagLunch 
          { Bag=bag, Lunch=lunch};
var baglunches = qry.ToList();

修改
您需要修改select子句以处理BagLunch类的结构。

答案 1 :(得分:2)

如果您允许欺骗[午餐可以分为两袋] - 例如建议您有#bags^#lunches种可能性。

每个包都有自己独特的“选择”午餐
为了创造这些可能性 - 只需“选择”一个袋子的午餐,并递归地调用算法。每个午餐重复一次。

用于生成它们的伪代码:

generateAll(bags,lunches,sol):
  if (bags is empty):
      print sol
      return
  bag <- bags.first
  bags.remove(bag)
  for each lunch in lunches:
     sol.append(BagLunch(bag,lunch)
     generateAll(bags,lunches,sol)
     sol.removeLast()

答案 2 :(得分:0)

所以你想在保持秩序的同时超过n(k =行李,n =午餐)的k?我希望你可以假设k <= n,否则你会被空袋子困住......

我不想完全破坏你的作业,所以我只是指出你正确的方向。这需要递归。首先选择第一个袋子的午餐,然后选择剩下的k-1袋的午餐。如果您只剩下一个行李,请选择每个剩余的午餐,直到您完成。

编辑:

哦,午餐可以一次放在两个袋子里。所以它是n ^ k。最短的方法是使用上面建议的LINQ交叉连接,但感觉有点像作弊。相反,只需创建一个K元素的整数数组,用零填充它,然后开始向最右边的元素添加一个元素。当它到达N时,将其重置为零并将一个元素带到下一个元素。您只计算base-N中的K位数字。每次迭代后,您都可以输出行李分配。

答案 3 :(得分:0)

我有一个方法可以重新创建上面的示例。这种方法实际上是把袋子想象成一个数字的位置......因为如果你看一下你的例子,你可以把它读成11,12,13,21,22,23。然后是转换到基础Lunch.Count的问题。我也从这里偷了一个方法:https://stackoverflow.com/a/95331/483179转换为它提到的未经测试的任何基础,因此你可能需要构建更健壮的东西。最后,我没有进行任何边缘条件测试,所以喂0袋可能会产生意想不到的结果。这就是我想出的。

class Program
{
    static List<Bag> bags = new List<Bag>();
    static List<Lunch> lunches = new List<Lunch>();

    static void Main(string[] args)
    {
        lunches.Add(new Lunch() { Num = 1 });
        lunches.Add(new Lunch() { Num = 2 });
        lunches.Add(new Lunch() { Num = 3 });
        bags.Add(new Bag() { Num = 1 });
        bags.Add(new Bag() { Num = 2 });

        int count = 0;
        while (count < Math.Pow(lunches.Count, bags.Count))
        {
            Console.WriteLine("Permutation " + count);
            string countNumber = ConvertToBase(count, lunches.Count).PadLeft(bags.Count,'0');
            for (int x = 0; x < bags.Count; x++)
            {
                Console.WriteLine(bags[x] + " " + lunches[Convert.ToInt32((""+countNumber[x]))]);

            }
            Console.WriteLine("");
            count++;
        }
        Console.ReadLine();

    }

    static string ConvertToBase(int value, int toBase)
    {
        if (toBase < 2 || toBase > 36) throw new ArgumentException("toBase");
        if (value < 0) throw new ArgumentException("value");

        if (value == 0) return "0"; //0 would skip while loop

        string AlphaCodes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        string retVal = "";

        while (value > 0)
        {
            retVal = AlphaCodes[value % toBase] + retVal;
            value /= toBase;
        }

        return retVal;
    }

}

class Lunch
{
    public int Num { get;set;}
    public override string  ToString()
    {
         return "Lunch " + Num;
    }

}
class Bag
{
    public int Num { get;set;}   

    public override string  ToString()
    {
         return "Bag " + Num;
    }
}

和结果输出:

Permutation 0
Bag 1 Lunch 1
Bag 2 Lunch 1

Permutation 1
Bag 1 Lunch 1
Bag 2 Lunch 2

Permutation 2
Bag 1 Lunch 1
Bag 2 Lunch 3

Permutation 3
Bag 1 Lunch 2
Bag 2 Lunch 1

Permutation 4
Bag 1 Lunch 2
Bag 2 Lunch 2

Permutation 5
Bag 1 Lunch 2
Bag 2 Lunch 3

Permutation 6
Bag 1 Lunch 3
Bag 2 Lunch 1

Permutation 7
Bag 1 Lunch 3
Bag 2 Lunch 2

Permutation 8
Bag 1 Lunch 3
Bag 2 Lunch 3