1

尝试解决以下任务时:

使用算术运算符(+、-、*、/)重新排列四个五以等于数字 1 到 10。

示例:5/5+5-5 =1 ,5/5+5/5=2

我在没有使用 Linq 的情况下尝试了 C#(我不知道如何继续进行)

public void GetDetails()
{

   char[] sym = new char[] { '+', '-', '/', '*' };

   int[] AOf5 = new int[] { 5, 5, 5, 5 };


for (int i = 0; i <4; i++)
 {
    for (int j = 0; j <4; j++)
     {
       for (int k = 0; k <4; k++)
          {
             for (int l = 0; l < 4; l++)
              {

                int result1 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
                AOf5[2] + sym[k] + AOf5[3];

               int result2 = AOf5[0] + sym[i] + AOf5[1] + sym[j] +
               AOf5[2] + sym[l] + AOf5[3];

              int result3 = AOf5[0] + sym[i] + AOf5[1] +
              sym[k] + AOf5[2] + sym[l] + AOf5[3];
              ....
              ....

              }  

         }

      }
  }

}

如果没有 linq 和使用 linq,我将无法完成它。期待您的帮助。

4

5 回答 5

4

应用从左到右(无优先级),我可以得到:

1: ((5+5)-5)/5
2:
3: ((5+5)+5)/5
4: ((5*5)-5)/5
5: ((5-5)*5)+5
6: ((5*5)+5)/5
7: ((5+5)/5)+5
8:
9:
10: ((5+5)+5)-5

使用(编辑:哎呀——“无 div”的东西是不必要的):

    var operators = new[] {
          new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
          new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
          new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
          new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
      };
    var options = from i in Enumerable.Range(1, 10)
                  select new {i, op=(
                    from op1 in operators
                    let v1 = op1.Func(5,5)
                    from op2 in operators
                    let v2 = op2.Func(v1, 5)
                    from op3 in operators
                    let v3 = op3.Func(v2,5)
                    where v3 == i
                    select "((5" + op1.Name + "5)" + op2.Name + "5)"
                       + op3.Name + "5").FirstOrDefault()};
    foreach (var opt in options)
    {
        Console.WriteLine(opt.i + ": " + opt.op);
    }
于 2009-10-18T10:06:11.813 回答
2

我以一种原始的方式做到了,我不确定答案是否正确。不过,在电子表格中更容易完成。基本上我修改了 linqfying 的代码来生成代码。

就这个:

public static void GetDetails()
{
    int ctr = 0;
    char[] sym = new char[] { '+', '-', '/', '*' };
    string num = "5";
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            for (int k = 0; k < 4; k++)
            {
                for (int l = 0; l < 4; l++)
                {
                    ctr++;
                    string str = num + sym[i] + num + sym[j] + num + sym[k] + num;
                    Console.WriteLine("res = " + str + "; ");
                    Console.WriteLine("if(res>=1 && res<=10)");
                    Console.WriteLine("Console.WriteLine(\"" + str + "\");");
                }

            }

        }
    }
    //Console.WriteLine("Total:" + ctr.ToString());
}

它生成 256 组操作,我将它们输出到一个文本文件中,将它们复制并粘贴到一个新方法中:

public static void runit()
{
    float res = 0;
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    res = 5+5+5+5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5+5+5+5");
    //......
    //......
    //......
    //......
    res = 5*5*5*5;
    if (res >= 1 && res <= 10)
        Console.WriteLine("5*5*5*5");

}

再次运行它,我得到了 76 个非唯一操作,这些操作介于 1 到 10 之间。这里有 19 个唯一操作(仅限从左到右的操作):

5*5/5/5
5*5/5+5
5/5*5/5
5/5*5+5
5/5/5+5
5/5+5/5
5/5+5-5
5/5-5+5
5+5*5/5
5+5/5*5
5+5/5/5
5+5/5-5
5+5+5-5
5+5-5/5
5+5-5+5
5-5/5/5
5-5/5+5
5-5+5/5
5-5+5+5

我敢肯定有人可以提出更有创意的东西:P

加上:

在与 Marc 的答案匹配后,我意识到最初的循环并未涵盖所有排列,我的答案不会是正确的。但既然我已经花了很长时间,我就让它留下来。:P

于 2009-10-18T10:10:08.497 回答
2

Marc 的解决方案中唯一缺少的情况是具有操作优先级的情况,例如:5/5+5/5。我将它们添加到联合中,这是正确的查询。
马克,如果你用下面的代码更新你的答案(如果你认为它是正确的)我会删除这个答案:

var operators = new[] {
              new { Name = "+", Func = (Func<decimal,decimal,decimal>)((x,y)=>x+y) },
              new { Name = "-", Func = (Func<decimal,decimal,decimal>)((x,y)=>x-y) },
              new { Name = "/", Func = (Func<decimal,decimal,decimal>)((x,y)=>x/y) },
              new { Name = "*", Func = (Func<decimal,decimal,decimal>)((x,y)=>x*y) }
          };

var options = from i in Enumerable.Range(1, 10)
              select new
              {
                  i,
                  op = (
                      from op1 in operators
                      let v1 = op1.Func(5, 5)
                      from op2 in operators
                      let v2 = op2.Func(v1, 5)
                      from op3 in operators
                      let v3 = op3.Func(v2, 5)
                      where v3 == i
                      select "((5" + op1.Name + "5)" + op2.Name + "5)"
                         + op3.Name + "5")
                      .Union(
             //calculate 2 operations (the left and the right one),  
             //then operate them together.
                        from op1 in operators
                        let v1 = op1.Func(5, 5)
                        from op2 in operators
                        let v2 = op2.Func(5, 5)
                        from op3 in operators
                        let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2)
                        where v3 == i
                        select "(5" + op1.Name + "5)" + op2.Name + "(5"
                             + op3.Name + "5)"
                      ).FirstOrDefault()
              };

foreach (var opt in options)
        {
            Console.WriteLine(opt.i + ": " + opt.op);
        }

编辑
关于let v3 = (op3.Name == "/" && v2 == 0) ? null : (int?)op3.Func(v1, v2):这是避免除以 0 的一种非常有效的方法(可能会发生,因为您可以除以(5-5))。

我很确定你可以用更好的方式过滤它,但我留下它是为了强调这个问题可能会发生。

于 2009-10-18T10:53:09.333 回答
1

假设您不想使用 LINQ,这是一种实现方法。也就是说,它非常未优化,我建议在它之上使用更短的 LINQ 实现。(参见:Marc Gravell 的帖子。)

using System;
using System.Collections.Generic;

namespace MathIterator
{
  class Program
  {
    static readonly int[] _inputs = new int[] { 5, 5, 5, 5 };
    static readonly char[] _operations = new char[] { '+', '-', '*', '/' };
    static Dictionary<int, List<string>> _calculations = new Dictionary<int, List<string>>();

    static void Main(string[] args)
    {
      StartPermutation();
      PrintResults();
    }

    static void StartPermutation()
    {
      if (_inputs.Length > 0)
        Permute(1 /*index*/, _inputs[0], _inputs[0].ToString());    
    }

    static void Permute(int index, int result, string computation)
    {
      if (index == _inputs.Length)
      {
        if (!_calculations.ContainsKey(result))
        {
          _calculations[result] = new List<string>();
        }

        _calculations[result].Add(computation);
      }
      else
      {
        foreach (char operation in _operations)
        {
          string nextComputation = String.Format("({0} {1} {2})",computation, operation, _inputs[index]);
          int nextResult = result;

          switch (operation)
          {
            case '+':
              nextResult += _inputs[index];
              break;
            case '-':
              nextResult -= _inputs[index];
              break;
            case '*':
              nextResult *= _inputs[index];
              break;
            case '/':
              nextResult /= _inputs[index];
              break;
          }

          Permute(
            index + 1,
            nextResult,
            nextComputation);
        }
      }
    }

    static void PrintResults()
    {
      for (int i = 1; i <= 10; ++i)
      {
        if (_calculations.ContainsKey(i))
        {
          Console.WriteLine("Found {0} entries for key {1}", _calculations[i].Count, i);

          foreach (string calculation in _calculations[i])
          {
            Console.WriteLine(i + " = " + calculation);
          }
        }
        else
        {
          Console.WriteLine("No entry for key: " + i);
        }
      }
    }
  }
}

这是另一个实现。这一个遵循优先顺序。同样,我不建议这样解决。考虑到宽破折号(以将它们与减号区分开来),现在更是如此,但它似乎确实有效。

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace MathIterator
{
  class Program
  {
    static readonly int[] _inputs = new[] { 5, 5, 5, 5 };
    //HUGE hack, the '–' is a wide dash NOT a hyphen.
    static readonly char[][] _operationLevels = new[] { new[] { '*', '/' }, new[] { '+', '–' } };
    static List<string> _calculations = new List<string>();
    static Dictionary<int, List<string>> _results = new Dictionary<int, List<string>>();

    static void Main(string[] args)
    {
      StartPermutation();
      StartEvaluateCalculations();
      PrintResults();
    }

    static void StartPermutation()
    {
      if (_inputs.Length > 0)
        Permute(1 /*index*/, _inputs[0].ToString());    
    }

    static void Permute(int index, string computation)
    {
      if (index == _inputs.Length)
      {
        _calculations.Add(computation);
      }
      else
      {
        foreach (char[] operationLevel in _operationLevels)
        {
          foreach (char operation in operationLevel)
          {
            string nextComputation = String.Format("{0} {1} {2}", computation, operation, _inputs[index]);
            Permute(
              index + 1,
              nextComputation);
          }
        }
      }
    }

    static void StartEvaluateCalculations()
    {
      foreach (string calculation in _calculations)
      {
        int? result = EvaluateCalculation(calculation);

        if (result != null)
        {
          int intResult = (int) result;

          if (!_results.ContainsKey(intResult))
          {
            _results[intResult] = new List<string>();
          }

          _results[intResult].Add(calculation);            
        }
      }
    }

    static int? EvaluateCalculation(string calculation)
    {
      foreach (char[] operationLevel in _operationLevels)
      {
        string[] results = calculation.Split(operationLevel, 2);

        if (results.Length == 2)
        {
          int hitIndex = results[0].Length;

          Regex firstDigit = new Regex(@"^ -?\d+");
          Regex lastDigit = new Regex(@"-?\d+ $");

          string firstMatch = lastDigit.Match(results[0]).Value;
          int arg1 = int.Parse(firstMatch);

          string lastMatch = firstDigit.Match(results[1]).Value; 
          int arg2 = int.Parse(lastMatch);

          int result = 0;

          switch (calculation[hitIndex])
          {
            case '+':
              result = arg1 + arg2;
              break;
            //HUGE hack, the '–' is a wide dash NOT a hyphen.
            case '–':
              result = arg1 - arg2;
              break;
            case '*':
              result = arg1 * arg2;
              break;
            case '/':
              if ((arg2 != 0) && ((arg1 % arg2) == 0))
              {
                result = arg1 / arg2;
                break;
              }
              else
              {
                return null;
              }
          }

          string prePiece = calculation.Remove(hitIndex - 1 - arg1.ToString().Length);
          string postPiece = calculation.Substring(hitIndex + 1 + lastMatch.ToLower().Length);

          string nextCalculation = prePiece + result + postPiece;
          return EvaluateCalculation(nextCalculation);
        }
      }

      return int.Parse(calculation);
    }

    static void PrintResults()
    {
      for (int i = 1; i <= 10; ++i)
      {
        if (_results.ContainsKey(i))
        {
          Console.WriteLine("Found {0} entries for key {1}", _results[i].Count, i);

          foreach (string calculation in _results[i])
          {
            Console.WriteLine(i + " = " + calculation);
          }
        }
        else
        {
          Console.WriteLine("No entry for key: " + i);
        }
      }
    }
  }
}
于 2009-10-18T10:42:37.477 回答
1

这是一个完全基于 LINQ(方法语法)和后期评估的解决方案,它处理所有排列(不仅是从左到右):

static void Main()
{
    var solution = PermuteLength(4)
        .Where(p => Decimal.Floor(p.Value) == p.Value)
        .Where(p => p.Value <= 10 && p.Value >= 0)
        .OrderBy(p => p.Value);

    foreach (var p in solution)
    {
        Console.WriteLine(p.Formula + " = " + p.Value);
    }
}

public static Operator[] Operators = new[]
    {
        new Operator {Format = "({0} + {1})", Function = (x, y) => x + y},
        new Operator {Format = "({0} - {1})", Function = (x, y) => x - y},
        new Operator {Format = "({1} - {0})", Function = (x, y) => y - x},
        new Operator {Format = "({0} * {1})", Function = (x, y) => x * y},
        new Operator {Format = "({0} / {1})", Function = (x, y) => y == 0 ? 0 : x / y},
        new Operator {Format = "({1} / {0})", Function = (x, y) => x == 0 ? 0 : y / x},
    };

public static IEnumerable<Permutation> BasePermutation = new[] { new Permutation {Formula = "5", Value = 5m} };

private static IEnumerable<Permutation> PermuteLength(int length)
{
    if (length <= 1)
        return BasePermutation;

    var result = Enumerable.Empty<Permutation>();

    for (int i = 1; i <= length / 2; i++)
        result = result.Concat(Permute(PermuteLength(i), PermuteLength(length - i)));

    return result;
}

private static IEnumerable<Permutation> Permute(IEnumerable<Permutation> left, IEnumerable<Permutation> right)
{
    IEnumerable<IEnumerable<IEnumerable<Permutation>>> product = left.Select(l => right.Select(r => ApplyOperators(l, r)));

    var aggregate =
        product.Aggregate(Enumerable.Empty<IEnumerable<Permutation>>(), (result, item) => result.Concat(item)).
            Aggregate(Enumerable.Empty<Permutation>(), (result, item) => result.Concat(item));

    return aggregate;
}

private static IEnumerable<Permutation> ApplyOperators(Permutation left, Permutation right)
{
    return Operators.Select(o => new Permutation
    {
        Formula = string.Format(o.Format, left.Formula, right.Formula),
        Value = o.Function(left.Value, right.Value)
    });
}

public struct Permutation
{
    public string Formula;
    public decimal Value;
}

public struct Operator
{
    public string Format;
    public Func<decimal, decimal, decimal> Function;
}

已知问题:一些解决方案是重复的,不能很好地处理除以零,所以一些错误的答案(我假设任何东西除以零 = 0)

编辑:结果的一部分:

((5 / 5) / (5 / 5)) = 1

((5 / 5) + (5 / 5)) = 2

((5 + (5 + 5)) / 5) = 3

(5 - ((5 + 5) / 5)) = 3

(((5 * 5) - 5) / 5) = 4

(5 + (5 * (5 - 5))) = 5

(5 - (5 * (5 - 5))) = 5

(5 + ((5 - 5) / 5)) = 5

(5 - ((5 - 5) / 5)) = 5

于 2009-10-18T14:41:36.260 回答