在游戏中工作并且在游戏中的某个时刻玩家被投入奖励游戏。他们需要获得的金额是预先确定的,但是我们想要提出一种算法,该算法使用加法,乘法和除法来获得x个步骤中的数量。步骤的数量也会提前知道,因此算法只需要弄清楚如何使用这些步骤来达到数字。
您可以使用的唯一计算是+1到+ 15,x2,x4,/ 2,/ 4。 您可以在步骤中超过目标编号,但必须以最后一步的目标编号结束。步数通常在15到30之间,您始终从0开始。
例如: 金额:100,步数:10 == + 10,+ 2,x2,+ 4,x4,+ 10,/ 2,+ 15,+ 15,+ 9
金额:40,步数:12 == + 15,+ 1,+ 5,+ 2,+ 1,/ 2,* 4,+ 6,+ 6,/ 4,+ 5,* 2
我很好奇是否有这样的东西可能已经存在?我确信我们可以拿出一些东西,但如果有一个可以处理这项工作的通用算法,我不想重新发明轮子。
更新:对@FryGuy的代码进行了一些小的更改,使其成为一个随机达到目标数量所需的路线。他的解决方案原样很有效,但在看到它工作并考虑到@Argote和@Moron的评论之后,我意识到需要在其中进行一定程度的随机化以使其吸引我们的玩家。在10个步骤中添加了+1,以达到目标数量为10的作品,但就我们如何使用它而言“无聊”。非常感谢所有评论和回答的人。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CR
{
class Program
{
static void Main(string[] args)
{
while (true)
{
int targetNumber = 20;
int steps = 13;
int[] route = null;
Boolean routeAcceptable = false;
// Continue choosing routes until we find one that is acceptable (doesn't average above or target win, but does exceed it at least once)
while(!routeAcceptable)
{
routeAcceptable = CalculateRoute(targetNumber, steps, out route) && route.Average() < targetNumber && route.Max() > targetNumber;
}
foreach (int i in route.Reverse())
{
Console.WriteLine(i);
}
Console.WriteLine("-----------------------");
Console.ReadLine();
}
}
static Boolean CalculateRoute(int targetNumber, int numSteps, out int[] route)
{
int maxValue = targetNumber * 16;
bool[,] reachable = new bool[numSteps + 1, maxValue];
// build up the map
reachable[0, 0] = true;
for (int step = 0; step < numSteps; step++)
{
for (int n = 0; n < maxValue; n++)
{
if (reachable[step, n])
{
foreach (int nextNum in ReachableNumbersFrom(n))
{
if (nextNum < maxValue && nextNum > 0)
{
reachable[step + 1, nextNum] = true;
}
}
}
}
}
// figure out how we got there
int[] routeTaken = new int[numSteps + 1];
int current = targetNumber;
for (int step = numSteps; step >= 0; step--)
{
routeTaken[step] = current;
bool good = false;
// Randomize the reachable numbers enumeration to make the route 'interesting'
foreach (int prev in RandomizedIEnumerbale(ReachableNumbersFromReverse(current)))
{
if (prev < targetNumber * 8)
{
if (reachable[step, prev])
{
current = prev;
good = true;
// Avoid hitting the same number twice, again to make the route 'interesting'
for (int c = numSteps; c >= 0; c--)
{
reachable[c, prev] = false;
}
break;
}
}
}
if (!good)
{
route = routeTaken;
return false;
}
}
route = routeTaken;
return true;
}
static IEnumerable<int> ReachableNumbersFrom(int n)
{
// additions
for (int i = 1; i <= 15; i++)
{
yield return n + i;
}
// mults/divides
yield return n / 2;
yield return n / 4;
yield return n * 2;
yield return n * 4;
}
static IEnumerable<int> ReachableNumbersFromReverse(int n)
{
// additions
for (int i = 1; i <= 15; i++)
{
if (n - i >= 0)
yield return n - i;
}
// mults/divides
if (n % 2 == 0)
yield return n / 2;
if (n % 4 == 0)
yield return n / 4;
yield return n * 2;
yield return n * 4;
}
static IEnumerable<int> RandomizedIEnumerbale(IEnumerable<int> enumerbale)
{
Random random = new Random(System.DateTime.Now.Millisecond);
return (
from r in
(
from num in enumerbale
select new { Num = num, Order = random.Next() }
)
orderby r.Order
select r.Num
);
}
}
}
答案 0 :(得分:10)
我会使用动态编程。首先,构建一个可以从每个步骤到达哪个数字的地图,然后回溯以了解如何到达那里:
void CalculateRoute(int targetNumber, int numSteps)
{
int maxValue = targetNumber * 16;
bool[,] reachable = new bool[numSteps + 1, maxValue];
// build up the map
reachable[0, 0] = true;
for (int step = 0; step < numSteps; step++)
{
for (int n = 0; n < maxValue; n++)
{
if (reachable[step, n])
{
foreach (int nextNum in ReachableNumbersFrom(n))
{
if (nextNum < maxValue && nextNum >= 0)
reachable[step + 1, nextNum] = true;
}
}
}
}
// figure out how we got there
int current = targetNumber;
for (int step = numSteps; step >= 0; step--)
{
Console.WriteLine(current);
bool good = false;
foreach (int prev in ReachableNumbersFromReverse(current))
{
if (reachable[step, prev])
{
current = prev;
good = true;
break;
}
}
if (!good)
{
Console.WriteLine("Unable to proceed");
break;
}
}
}
IEnumerable<int> ReachableNumbersFrom(int n)
{
// additions
for (int i = 1; i <= 15; i++)
yield return n + i;
// mults/divides
yield return n / 2;
yield return n / 4;
yield return n * 2;
yield return n * 4;
}
IEnumerable<int> ReachableNumbersFromReverse(int n)
{
// additions
for (int i = 1; i <= 15; i++)
yield return n - i;
// mults/divides
if (n % 2 == 0)
yield return n / 2;
if (n % 4 == 0)
yield return n / 4;
yield return n * 2;
yield return n * 4;
}
答案 1 :(得分:4)
从您想要的解决方案向后工作
如果您的除法和乘法仅为2和4,则可以很容易地知道何时可以执行或不执行这些操作
然后,在最后的4-5步中你可以任意返回0
添加到此;您可以在初始阶段使用随机操作,检查您是否未执行非法操作,还应包括范围检查。您不希望最终得到400这样的数字,然后将其作为最后一次操作分成4次,以便回到0。
答案 2 :(得分:3)
你可以使用N级深度的搜索树来强制它,其中N是步数。这将是O(m ^ n),其中m是允许的操作数。
可能有更好的算法,但这适用于较小的N值。
例如,使用{广度,深度} - 第一次搜索或A *。