有没有比蛮力更有效的创建数组版本的方法?

时间:2016-05-02 08:45:33

标签: c# scenarios

我有一个bool[],我希望从原始数组中生成数组的版本/方案并将其保存到list<bool[]>

如果数组看起来像{true,true,false,true,true,true}。我们的想法是,如果bool[0]bool[1]都为真且bool[2]为假。我想创建一个方案,其中bool[0]bool[1]为false且bool[2]为true,并将该方案添加到我的列表中。我目前正在for循环中执行此操作,以检查数组中的每个插槽{true,true,false}{false, true,true}。目标是找到我在数组中尽可能少bool = true元素并返回该数组的场景。

我试图用蛮力来做这件事,但它太慢了(有时几分钟)。我想要它的语言是C#。创建场景是否比使用暴力更有效?

我生成场景的代码:

class Program
{
    public static List<bool[]> alternativs = new List<bool[]>();
    public static int arrayCount = 23;
    public static int tempCount = 0;
    static void Main(string[] args)
    {
        //this works fast
        bool[] easyInput = new bool[23] { true, true, false, false, false, false, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false };
        //this takes forever
        bool[] hardInput = new bool[23] { true, true, false, true, true, false, true, true, false, true, true, false, true, true, false, true, true, false, true, true, false, true, true };

        alternativs.Add(easyInput);
        while (alternativs.Count > 0)
        {
            for (int i = 0; i < 21; i++)
            {
                if (alternativs[0][i] == true && alternativs[0][i + 1] == true && alternativs[0][i + 2] == false)
                {
                    bool[] temp = new bool[23];
                    bool[] temp3 = new bool[23];

                    Array.Copy(alternativs[0], temp, 23);
                    Array.Copy(temp, temp3, 23);
                    Array.Reverse(temp3);
                    temp[i] = false;
                    temp[i + 1] = false;
                    temp[i + 2] = true;

                    if (!alternativs.Contains(temp) && !alternativs.Contains(temp3))
                    {
                        alternativs.Add(temp);
                    }
                }
                if (alternativs[0][i] == false && alternativs[0][i + 1] == true && alternativs[0][i + 2] == true)
                {
                    bool[] temp2 = new bool[23];
                    bool[] temp4 = new bool[23];

                    Array.Copy(alternativs[0], temp2, 23);
                    Array.Copy(temp2, temp4, 23);

                    temp2[i] = true;
                    temp2[i + 1] = false;
                    temp2[i + 2] = false;
                    if (!alternativs.Contains(temp2) && !alternativs.Contains(temp4))
                    {
                        alternativs.Add(temp2);
                    }
                }
            }
            tempCount = 0;
            for (int j = 0; j < 23; j++)
            {
                if (alternativs[0][j] == true)
                    tempCount++;
            }
            if (tempCount < arrayCount)
            {
                arrayCount = tempCount;
            }
            alternativs.RemoveAt(0);
        }
        Console.WriteLine(arrayCount);
    }
}

经过一些修改后,代码如下所示:

class Program
{
    public static List<string> alternativs = new List<string>();
    public static int arrayCount = 23;
    public static int tempCount = 0;
    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        //this works fast
        //string easyInput = "11000011110000000000000";
        //this takes forever
        string hardInput = "11011011011011011011011";
        string xtra = "00101100011010000000000";

        string TmpVal = "";
        string RevVal = "";

        alternativs.Add(xtra);
        while (alternativs.Count > 0)
        {
            if (alternativs[0].Contains("110"))
            {
                TmpVal = alternativs[0];
                TmpVal = TmpVal.Replace("110", "001");
                RevVal = string.Concat(Enumerable.Reverse(TmpVal)); //String Reverse

                if (!alternativs.Any(xs => xs.SequenceEqual(TmpVal)) && !alternativs.Any(xs => xs.SequenceEqual(RevVal)))
                {
                    alternativs.Add(TmpVal);
                }
            }
            if (alternativs[0].Contains("011"))
            {
                TmpVal = alternativs[0];
                TmpVal = TmpVal.Replace("011", "100");
                RevVal = string.Concat(Enumerable.Reverse(TmpVal)); //String Reverse

                if (!alternativs.Any(xs => xs.SequenceEqual(TmpVal)) && !alternativs.Any(xs => xs.SequenceEqual(RevVal)))
                {
                    alternativs.Add(TmpVal);
                }

            }

            tempCount = alternativs[0].Count(x => x == '1');
            if (tempCount < arrayCount)
            {
                arrayCount = tempCount;
            }
            alternativs.RemoveAt(0);

        }
        Console.WriteLine(arrayCount);
        sw.Stop();
        Console.WriteLine(sw.Elapsed);
        Console.ReadLine();
    }
}

根据要求,我将完成从原始数组到尽可能少{true}的数组的过程。在下面的示例中,我将1true0使用false

我将使用一个简单的例子,并展示如何手动完成:

这是输入数组{0110100101011},我们称之为myInput。 第1步:我选择1表单myInput[1]并跳过myInput[2]并登陆myInput[3]。这会将myIput[1]转换为0myInput[2]转换为0myInput[3]转换为1。 此移动生成的数组为{0001100101011}。 如果我在myInput[2]上移动myInput[1],则myInput[2]必须跳转到myInput[0]并生成类似{1000100101011}的数组。这样就无法删除1处的myInput[4],因为它现在被0包围了。

让我们继续第一个正确的举动,结果是{0001100101011}。我要做的下一步是myInput[3]myInut[5]。给我们这个结果{0000010101011}。然后myInput[12]myInput[10]。结果{0000010101100}myInput[10]myInput[8]。结果{0000010110000}myInput[8]myInput[6]。结果{0000011000000}。最后,myInput[6]myInput[4]。结果{0000100000000}。 给我们一个1数组{0001100101011}的结果,因为没有更多可行的动作。

由于我编写的程序必须检查所有不同的动作,并且无法确定将1myInput[2]移动到myInput[0]开始是不明智的我必须对不同的动作进行程序测试并将它们存储到我的列表alternativs中。这会产生大量的场景,这会减慢我的程序。

我仍然没有设法找到解决方案。

2 个答案:

答案 0 :(得分:0)

我仍然不明白你要做什么。希望它有所帮助。

使用另一种方法来加速程序。将所有true替换为1,将所有false替换为0.而不是将字节数组存储在字符串中。结果容易= 3而硬= 16。

class Program
{
    public static List<string> alternativs = new List<string>();
    public static int arrayCount = 23;
    public static int tempCount = 0;
    static void Main(string[] args)
    {
        //this works fast
        string easyInput = "11000011110000000000000";
        //this takes forever
        string hardInput = "11011011011011011011011";

        string TmpVal = "";
        string RevVal = "";
        bool CanAdd;

        alternativs.Add(hardInput);
        while (alternativs.Count > 0)
        {
            CanAdd = false;
            if (alternativs[0].Contains("110"))
            {
                TmpVal = alternativs[0];
                RevVal = string.Concat(Enumerable.Reverse(TmpVal)); //String Reverse
                TmpVal = TmpVal.Replace("110", "001");
                CanAdd = true;
            }
            if (alternativs[0].Contains("011"))
            {
                TmpVal = alternativs[0];
                RevVal = string.Concat(Enumerable.Reverse(TmpVal)); //String Reverse
                TmpVal = TmpVal.Replace("011", "100");
                CanAdd = true;
            }
            if (CanAdd == true)
            {
                if (!alternativs.Contains(TmpVal) && !alternativs.Contains(RevVal))
                {
                    alternativs.Add(TmpVal);
                }
            }
            tempCount = alternativs[0].Count(x => x == '1');
            if (tempCount < arrayCount)
            {
                arrayCount = tempCount;
            }
            alternativs.RemoveAt(0);

        }
        Console.WriteLine(arrayCount);
        Console.ReadLine();
    }
}

事实证明,如果你需要最少的真数,上面的代码只是平面复杂和不正确。请仔细阅读下面的代码......得到的结果是8。

class Program
{
    public static string CurStr;
    public static int arrayCount = 23;
    public static int tempCount = 0;
    static void Main(string[] args)
    {
        //this works fast
        string easyInput = "11000011110000000000000";
        //this takes forever
        string hardInput = "11011011011011011011011";

        string TmpVal = "";
        bool CanAdd;

        CurStr = hardInput;
        CanAdd = true;
        while (CanAdd)
        {
            TmpVal = CurStr;
            CanAdd = false;
            if (TmpVal.Contains("110"))
            {
                TmpVal = TmpVal.Replace("110", "001");
                CanAdd = true;
            }
            if (TmpVal.Contains("011"))
            {
                TmpVal = TmpVal.Replace("011", "100");
                CanAdd = true;
            }
            if (CanAdd == true)
            {
                CurStr = TmpVal;
            }
            tempCount = CurStr.Count(x => x == '1');
            if (tempCount < arrayCount)
            {
                arrayCount = tempCount;
            }
        }
        Console.WriteLine(arrayCount);
        Console.ReadLine();
    }
}

答案 1 :(得分:0)

我认为您遇到了.Contains运营商的问题。

如果您有此代码:

var list_of_bool_arrays = new List<bool[]>()
{
    new [] { true, false },
};

Console.WriteLine(list_of_bool_arrays.Contains(new [] { true, false }));

...您可能希望它打印True - 很明显,数组new [] { true, false }位于数组列表中。但它会打印False。数组是引用类型,仅在引用相同而不是内容时报告相等。

要获得True,您需要执行以下代码:

Console.WriteLine(list_of_bool_arrays.Any(xs => xs.SequenceEqual(new [] { true, false })));

所以现在我只是在代码中重写了这些行:

if (!alternativs.Any(xs => xs.SequenceEqual(temp)) && !alternativs.Any(xs => xs.SequenceEqual(temp3)))

...和

if (!alternativs.Any(xs => xs.SequenceEqual(temp2)) && !alternativs.Any(xs => xs.SequenceEqual(temp4)))

然后代码几乎立即运行hardInput,结果为16