老赵的自然数分解——少侠之对象解
前几天贴了个非递归的 今天继续搞一个使用对象的解
坚持用对象来解决问题的一个原因,是想证明使用面向对象不是造成算法速度慢的根本原因
例如,我这个面向对象的解,其运行速度似乎很牛的说,至少比我自己的非递归解要快10%。
核心类Item,代表算式中的每个项
派生类Tail,是最末尾的一项
主控类Splitter,负责构造以及输出
嫌文章太长的直接看源代码
另外,Cat Chen的代码要简洁得多了,值得学习。 并且对于本问题的分析也比我说得要更清晰。
delegate void OverflowEventHandler();
delegate void AddedEventHandler(Item item);
class Item
{
//回溯起点对象
public static Item StartItem { get; set; }
//总项数,最大值,最小值
public static int N { get; set; }
public static int Max { get; set; }
public static int Min { get; set; }
public static int Count { get; set; }
//事件
public event OverflowEventHandler Overflow;
public event AddedEventHandler Added;
//
private int _index, _remainN;
private int _subSum;
protected int _value;
//仅为了给尾部对象读取
public int SubSum { get { return _subSum; } }
public Item() { }
public Item(int index,ref int sum)
{
_index=index;
_remainN = (N - index-1 );
if (sum <= _remainN * Max)
{
_value = Min;
}
else
{
_value = sum - _remainN * Max;
}
//检查并设置回溯位置
CheckState(sum);
sum -= _value;
_subSum = sum;
}
public void Add()
{
if (_value < (_subSum + _value) / (_remainN + 1))
{//如果没有达到当前位置的最大允许值,递增自身
_value++;
_subSum--;
CheckState(_subSum);
//引发增加事件
Count++;
if (Added != null)
Added(this);
}
else
{//如果达到当前位置的最大允许值,引发溢出事件
if (Overflow != null)
{
Overflow();
}
}
}
public virtual void Reset(Item item)
{
//计算新的当前值
_value = item._subSum < _remainN * Max ? Min : item._subSum - _remainN * Max;
_value = Math.Max(_value, item._value);
_subSum = item._subSum-_value;
CheckState(_subSum);
Count++;
if (Added != null)
Added(this);
}
public override string ToString()
{
return _value.ToString();
}
private void CheckState(int sum)
{
//如果当前值小于允许最大值,则当前位置是回溯位置
if (_value < (sum + _value) / (_remainN + 1))
StartItem = this;
}
}
class Tail:Item
{
public new event AddedEventHandler Added;
public Tail(int sum)
{
_value = sum;
}
public override void Reset(Item item)
{
_value = item.SubSum;
if (Added != null)
Added(this);
}
}
class Splitter
{
//项目数足
Item[] _items;
StringBuilder _builder;
//记录当前结果,并引发下一次计算
void Splitter_Added(Item item)
{
_builder.AppendLine(string.Join("+",Array.ConvertAll(_items,i=>i.ToString())));
Item.StartItem.Add();
}
//第一个个项产生溢出,设置起点为空,终止计算
void Splitter_Overflow()
{
Item.StartItem = null;
}
public string PrintDivision(int sum, int n, int min, int max)
{
string returnValue = "";
Item.N = n;
Item.Max = max;
Item.Min = min;
_builder = new StringBuilder();
_items = new Item[n];
int i;
//构造项目数组
for (i = 0; i < n-1; i++)
{
_items[i] = new Item(i,ref sum);
if (i > 0)
{
//关联前后项目的事件
_items[i - 1].Added += _items[i].Reset;
_items[i].Overflow += _items[i - 1].Add;
}
}
//增加尾项目对象及其事件关联
_items[i] = new Tail(sum);
_items[i - 1].Added += _items[i].Reset;
//第一项溢出事件关联
_items[0].Overflow += new OverflowEventHandler(Splitter_Overflow);
//最后一项置位完成事件关联
_items[n - 1].Added += new AddedEventHandler(Splitter_Added);
//在存在未溢出位置时一直循环
while(Item.StartItem!=null)
//这里实参是不需要的,不想继续优化了,呵呵
Splitter_Added(_items[n - 1]);
//记录最后一次的结果
returnValue = _builder.ToString();
Console.WriteLine(Item.Count);
return returnValue;
}
}
class Program
{
static void Main(string[] args)
{
TimeSpan ts;
System.IO.StreamWriter w ;
string st;
DateTime dt;
w = new System.IO.StreamWriter("output.txt");
Splitter s = new Splitter();
dt = DateTime.Now;
st = s.PrintDivision(80, 25, 1, 30);
ts = DateTime.Now - dt;
Console.WriteLine( ts.TotalMilliseconds);
w.Write(st);
w.Close();
}
}
谢谢大家观赏
出处:http://www.cnblogs.com/Chinese-xu/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
如有问题,可以通过 Chinese_Xu@126.com 联系我,非常感谢。