按:之所以用小结局而非大结局,因为笔者的解法并没有给出理论上的全部解,只是给出了大部分解法。
算法描述如下
#1 初始化
#完成七巧板组件的初始化以及盛放七巧板的容器的初始化;
#2 采用DFS 方法获得解集合并记录
#3 以图片方式输出结果
采用堆栈实现的复原核心伪代码如下:
private void PutTPartInBox(TangramPartSet tgPartSet)
{
//1# prepare the components of the tangram
.....
// DFS to find a solution
while (!m_Stop)
{
///##################################################################################
#region 1 Take a part from the lib , TAKE A NEW ONE FROM THE LIB
///##################################################################################
if (bTakeFromLib)
{
curPart = tgPartSet.GetOtherPartFromLib(curFailedParts);
if (curPart != null)// if the lib is not empty
{
InitialilizeTheComponents();
bTakeFromBox = false;// not take from the box
bToNextBoxIdx = false;
else // there is no required component in the lib
{
bTakeFromBox = true;// should take the components from the box(stack)
}
}
///##################################################################################
#endregion 1 Take one part from the LIB
///##################################################################################
//##################################################################################
#region 2 Take one part from the box(pop up) and addjust its position in the box.
//##################################################################################
if (bTakeFromBox)
{
if (tgPartSet.CountInBox() > 0)
{
curPart = tgPartSet.TakeLastPartFromBox();
}
else
{
//MessageBox.Show("All of the scenarios have been tried, commission complete.");
break;
}
}
//##################################################################################
#endregion 2 Take one part from the box
//##################################################################################
#region //################# state check ##########################
curBoxPlg = curPart.m_Plg.usingBoxPlg;
curPartPlg = curPart.m_Plg;
var statePlgCnt = curPartPlg.SatePlgCount;
var boxVtxCnt = curPartPlg.usingBoxPlg.Count();
bool bPartIdxEnd = curPartPlg.StatePlgIndex >= statePlgCnt - 1;
bool bBoxIdxEnd = curBoxPlg.usingIdx > boxVtxCnt - 1;
if (!bPartIdxEnd)// Try next state part polygon , inner loop,
{
curPartPlg.StatePlgIndex++;
}
else
{
if (!bBoxIdxEnd)//outer loop
{
curBoxPlg.usingIdx++;
curPartPlg.StatePlgIndex = 0;
}
else// all of the loop ended, put it to the lib and get another one
{
AddFailedPartForStep(curPart, FailedPartsForStep, tgPartSet.GetCurStep());
curFailedParts = _GetFailedPartForCurStep();
bTakeFromLib = true;
bTakeFromBox = false;
tgPartSet.ReturnPartToLib(curPart);
exePath += "3 ->Take another one " + string.Format("_{0} [{1}]_", curPart.m_No, _InBoxType());
continue;
}
}
#endregion //#################### state check ##############################
///##################################################################################
#region 3 Begin to adjust(Match) the part in the box (addjust its positon)
///##################################################################################
bMounted = CMyPolygonTool.MatchPolygon(curPartPlg, tgPartSet.m_MainBoxPlg, out outPart, pbxTestingBox);// check if the component can be put in the box
///##################################################################################
#endregion 3 Begin to adjust the part in the box (addjust its positon)
///##################################################################################
///##################################################################################
#region 4 The part can not be set in the box (not matched)
///##################################################################################
if (!bMounted)// Not matched , continue to take out component from the box( stack pop)
{
tgPartSet.PutPartInBox(curPart);// Put it in the box,, just to make for a loop, notice the stattus has been changed
bTakeFromLib = false;
bTakeFromBox = true;
continue;
}
///##################################################################################
#endregion 4 The part can not be set in the box (not match)
///##################################################################################
///##################################################################################
#region 5 The part CAN be set in the box (Matched)
///##################################################################################
if (bMounted)// this one can be put in the box , calcula the remainning area and take another part from lib
{
tgPartSet.PutPartInBox(curPart);// Put it in the box , and go on to take next part ( any type)
bTakeFromLib = true;
// initilize the failed part for this new level
if (FailedPartsForStep.TryGetValue(tgPartSet.GetCurStep(), out _))
{
FailedPartsForStep.Remove(tgPartSet.GetCurStep());
}
curFailedParts = "";
//######################################################
//######!!!! Find One !!!!!!!!!!! ################
//######################################################
if (tgPartSet.CountInBox() == tgPartSet.GetTotalParts())
{
RecordInReusltList();
bTakeFromLib = false;
bTakeFromBox = true;
continue;// succeed ,continue try to find another solution
}
//calculating the left area and get a new part to process
//2.3#
bTakeFromBox = false;
curBoxPlg = newPlyLst[0];
bTakeFromLib = true;
continue;// mounted in the box, to get a new part
}
///##################################################################################
#endregion 5 The part CAN be set in the box (Matched)
///##################################################################################
}
}
说明:上述算法中有两个核心容器:Lib 用于存放七巧板组件,Box(Stack)用于摆放七巧板,如果Lib容器为空,则说明完成了一个摆放, 将结果记录下来;否则回退,尝试下一个摆放;摆放中用到了前文提到的各种判断以及剩余区域的计算。摆放时对七巧板进行了旋转和反转操作,力图模仿七巧板的真实摆放情况,摆放时的具体算法采用左下优先贴合的方法,实际上这样摆放之后会漏掉右上摆放的部分解。如图示:
这两种方法对应的结果是不一样的,这也是本解法不完备的地方。
笔者思考了解决办法,终极解法就是在剩余空腔的集合中再分别使用本方法进行DFS。这样程序结构稍微复杂一点,实际代码并没有实现。
部分界面参考
1、七巧板设计界面
笔者尝试解决的实际七巧板的组件如下:
解法探索探索界面
一共找到216 中解法(应该是不重复的), 部分解法截图如下
代码还有待完善,但是…再议吧、
MaraSun 与 BJFWDQ
抗疫人在继续,人生何其苦长。
人啊,何必跟人较劲呢?