- 注册时间
- 2007-12-27
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 40218
- 在线时间
- 小时
|
发表于 2009-2-19 10:25:02
|
显示全部楼层
附件里面是两个程序.
其中finder用来搜索结果,sfilter用来淘汰结果(不完全淘汰,同样,我还有一个速度更慢但是效率更加高的不完全淘汰程序)
而程序的输入输出都是一行由大写字母构成的串,每四个字母构成一条直线(或者说一行树),每个字母代表一棵树.
在程序finder中,函数process_one_line将处理一行输入的结果(比如这里输入应该是14行17棵数的情况,所以每行56个字母)
这个函数第一部分将数据转化格式到line_buf[MAX_TOTAL_EDGES][NODES_PER_EDGE]; 全局变量line_count表示直线数目,比如这里初始化以后总是14.
然后程序使用了一个LLFilter类用来过滤一些不满足平面约束条件的解. 具体来说是这样的,如果我们将14条直线中任意一条投影到无穷远,那么这条直线上4棵树变成了4个无穷远点,所以所有相交与它们的直线变成了平行线.然后我们只考虑这些平行线的约束,看看是否存在平面上的解. 对于这4组平行线,可以将其中一组投影成同横坐标平行的直线(相交于LLFilter::node_x的直线),另外一组平行于纵坐标(相交于LLFilter::node_y的直线),然后再通过伸缩横坐标或纵坐标,可以将一组变成同y=x直线平行(相交与LLFilter::node_d1的直线),而对于第四组,可以假设它们平行于直线y/k=x,其中k是待定系数).
函数LLFilter::initFromGlobal就是使用这种方法来构造方程,首先是假设所有点的横纵坐标(这里直接使用了前两组平行关系),其中x_stat[],y_stat[]保存了每个点的横纵坐标对应的变量的索引. 另外还保存了xmc,ymc,xtc,ytc.其中xtc和ytc表示横坐标和纵坐标的总数,xmc和ymc表示其中前xmc个横坐标和前ymc个纵坐标是提供给多个点的(后面的都是一个点的横纵坐标)
然后函数LLFilter::initFromGlobal余下部分代码是根据另外两个方向的平行线构造一些线性方程,其中这些线性方程总共使用了xtc+2*ytc个变量,前xtc个代表各个横坐标,接下去ytc个代表各个纵坐标,最后ytc个代表各个y/k.
同时LLFilter::x_coord,LLFilter::y_coord保存了各个点横坐标和纵坐标用方程中参数的线性组合表示的方案.
最后调用LLFilter::linear_reduce()进行消元.
首先reduce_x尽量消去所有的横坐标,然后只保留那些仅使用了y和y/k形式变量的方程.
其次reduce_y尽量消去那些变量y,留下一些仅仅使用y/k形式变量的方程,对于这些方程其中1/k是公因子我们可以扔掉,所以得到了一些关于纵坐标的线性组合,由此可以将一些纵坐标用其它点的纵坐标的线性组合替换.
其中reduce_cols会进行消元并且将那些可以用其它的线性组合表示的y/k消掉
而replace_y_by_y2会将这些线性组合中的公因子1/k去除,然后将对应的y坐标直接对应的变量也消除.
同样类似有函数reduce_y2,它通过尽量消除变量y/k,留下一下仅仅使用y形式变量的方程,得到一些关于纵坐标的线性组合,然后同样替换掉一些变量.
最后simplify_col()函数只是仅仅调整了一下这些余下的参数的编号(很多变量被消元了)
其次是函数LLFilter::checkValid()用来判断是否出现矛盾,其标准很简单,就是前xmc个横坐标必须全部相互不同,而后面的xtc-xmc个变量相互之间可以相等,但是它们也不能同前xmc个相等(不然都不是果树问题的解),同样对于纵坐标也有类似的判断.
当然上面的判断方法通过不代表必然有解,所以程序使用了将所有不同直线作为无穷远直线的组合判断结果. 只要其中一个判断结果无解,那么必然无解.反之,就存在一个可能的候选结果需要进一步判断.
然后回到程序process_one_line的最后面,调用了一个递归函数search,这个函数的目的就是每次在前面的一个方案中间在添加一条直线(这条直线必然经过最后一个点,也就是先添加的点). 同样我们首先需要判断没有三点共线出现在两个不同直线上之类的简单判断,然后有到了调用LLFilter来过滤的情况.
为了仅可能提高效率,这里每次递归下去,我们都将原先的LLFilter复制一份,然后通过函数
LLFilter::addOneEdge 又添加了关于这一条新的边的信息,最次化简并判断是否无解.
所以所有的这些LLFilter构成了一个二维数组
LLFilter gFilter[FILTER_COUNT][INIT_EDGES];
而其中FILTER_COUNT是递归可能达到的最大深度的一个上界.
INIT_EDGES是所有被当成无穷远直线的直线数目,也就是输入方案的直线数目(比如这里是14) |
|