好吧,假设我有一个具有“州”特权的班级foo
。我需要一个随机选择具有这些限制的新状态的函数:不允许某些转换,并且每个转换都有不同的发生概率。
enum PossibleStates { A, B, C, D }
PossibleStates currentState;
float[,] probabilities;
probabilities[s1, s2]
表示从状态s1进入状态s2的概率。它也可以是0.0f,意味着s1-> s2是不可能的,probabilities[s1, s2]
可以与probabilities[s2, s1]
不同。我需要这种方法尽可能通用,这样就可以有三种以及三百种可能的状态
这不是功课,我只需要一个很好的起点,因为我不知道从哪里开始:)
干杯
答案 0 :(得分:2)
对于从状态A的转换,您在0和1之间计算(均匀分布的)随机数r
。您具有转换的概率:p1
,p2
,. ..,pn
,他们的总和显然必须是1.现在,如果r < p1
,你遵循第一次过渡;否则,如果r < p1 + p2
,则按照第二次转换进行操作,依此类推。
P.S。:为了产生所需的随机数,你得到一个(单个)Random
个对象,并调用NextDouble
方法:
Random rnd = new Random();
...
double r = rnd.NextDouble();
答案 1 :(得分:1)
好的,我们假设我们有一个函数可以产生1到100之间的随机值。
让我们调用这个函数
float GetRandomNumber()
{
....
}
现在我们假设我们想要生成三个在两种情况下可能发生的数字:
案例1)
概率是互斥的,即如果一个发生,其他概率就不会发生
案例2)
概率是独立的,因此它们以自己的概率发生
让我们看看1:
发生了什么 var mutuallyExclusiveProbs = new List<float>({30,50,20});
var number = GetRandomNumber();
var cumulativeValue =0;
//
for (int i=0; i++; i<mutuallyExclusiveProbs.Count())
{
cumulativeValue += mutuallyExclusiveProbs(i)
if (number <=cumulativeValue)
{
//case found
return i;
}
}
而对于2则更容易
var mutuallyExclusiveProbs = new List<float>({30,50,20});
var number = GetRandomNumber();
return mutuallyExclusiveProbs.Where(x=>x<=number );
我已直接编写代码,但可能无法编译,但我认为我正在做的事情已经显示出来了。
希望它有所帮助。
答案 2 :(得分:1)
完整功能示例如下。 F5然后点击ENTER改变状态。
在States
课程中,您可以定义概率和状态。
在我的代码中我假设路由是互斥的(它们的组合概率永远不会超过1)。如果不是这样的话,我已经标记了要改变的代码。
namespace RandomStatesProgram
{
class State
{
public string Name;
private bool current;
public bool Current
{
get { return current; }
set
{
if (current)
{
if (value) StayingHere();
else LeavingState();
}
else
{
if (value) EnteringState();
}
current = value;
}
}
public void StayingHere() { Console.WriteLine("Staying in state " + this.Name); }
public void EnteringState() { Console.WriteLine("Entering state " + this.Name); }
public void LeavingState() { Console.WriteLine("Leaving state " + this.Name); }
public State()
{
this.Name = "New";
this.Current = false;
}
public State(string name)
: this()
{
this.Name = name;
}
}
class TransitionCourse
{
public State From { get; set; }
public State To { get; set; }
public float Probability { get; set; }
public TransitionCourse(Dictionary<int, State> allStates, int fromState, int toState, float probability)
{
if (probability < 0 || probability > 1)
throw new ArgumentOutOfRangeException("Invalid probability");
if (!allStates.Keys.Any(K => K == fromState || K == toState))
throw new ArgumentException("State not found");
this.From = allStates[fromState];
this.To = allStates[toState];
this.Probability = probability;
}
}
static class States
{
private static Dictionary<int, State> PossibleStates;
public static State Current
{
get
{
if (PossibleStates.Where(S => S.Value.Current).Count() == 1)
return PossibleStates.Single(S => S.Value.Current).Value;
else
return null;
}
}
public static List<TransitionCourse> Transitions;
static States()
{
PossibleStates = new Dictionary<int, State>()
{
{1, new State("One")},
{2, new State("Two")},
{3, new State("Three")},
{4, new State("Four")}
};
// example: 50% chance of switching to either state from every one of the three
// note: it must be 0 <= 3rd param <= 1 of course (it's a probability)
Transitions = new List<TransitionCourse>()
{
new TransitionCourse(PossibleStates,1,2,1f/3f),
new TransitionCourse(PossibleStates,1,3,1f/3f),
new TransitionCourse(PossibleStates,1,4,1f/3f),
new TransitionCourse(PossibleStates,2,1,1f),
new TransitionCourse(PossibleStates,3,1,1f),
new TransitionCourse(PossibleStates,4,1,1f)
};
}
public static void GoTo(int targetState)
{
if (!PossibleStates.Keys.Contains(targetState))
throw new ArgumentException("Invalid state");
foreach (KeyValuePair<int, State> state in PossibleStates.OrderByDescending(S=>S.Value.Current))
{
//first is the "true" state (the current one) then the others.
//this way we go OUT from a state before going IN another one.
state.Value.Current = state.Key.Equals(targetState);
}
}
public static void Travel()
{
if (Current == null)
throw new InvalidOperationException("Current state not set");
TransitionCourse[] exits = Transitions.Where(T => T.From.Equals(Current)).OrderBy(T=>T.Probability).ToArray();
if (exits.Length == 0) //nowhere to go from here
return;
else
if (exits.Length == 1) //not much to choose here
{
GoTo(PossibleStates.Single(S => S.Value.Equals(exits.First().To)).Key);
}
else //ok now we have a choice
{
//we need a "random" number
double p = new Random().NextDouble();
// remapping probabilities so we can choose "randomly"
// this works IF the sum of all transitions probability does not exceed 1.
// if it does, at best this'll act weird
for (int i = 1; i < exits.Length; i++)
{
exits[i].Probability += exits[i - 1].Probability;
if (exits[i].Probability > p)
{
GoTo(PossibleStates.Single(S => S.Value.Equals(exits[i].To)).Key);
return;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
States.GoTo(1);
while (Console.ReadLine().ToUpper() != "Q")
{
States.Travel();
}
}
}
}