苏州中学 关键字: 【摘要】
数学模型是解决实际问题的一种基本工具。将实际问题抽象成一个数学模型,运用数学工具进行求解,并将结果应用于具有相同特征的一类问题中,是解决问题的一种基本的途径。本文首先介绍了数学模型的一些性质,然后建立了三种不同的数学模型来求解一个问题,将三种数学模型相互比较,得出数学模型抽象性与高效性之间的关系,再将数学模型推广应用于另两个问题的求解,得出数学模型抽象性与可推广性之间的关系,最后总结全文,揭示出有关数学模型的一些普遍规律。
一、引论
实际问题往往是纷繁而复杂的,而其中的规律也是隐藏着的,要想直接用计算机来求解实际问题往往有一定的困难。计算机擅长的是解决数学问题。因此,我们有必要将实际问题抽象成数学模型,然后再用计算机来对数学模型进行求解。
与实际问题相比,数学模型有以下几个性质:
抽象性:数学模型是实际问题的一种抽象,它去除了实际问题中与问题的求解无关的部分,简明地体现了问题的本质。这一点是下面两个性质的基础。
高效性:数学模型中各个量之间的关系更为清晰,容易从中找到规律,从而提高求解的效率。由于这一点是由数学模型的抽象性决定的,因此数学模型的抽象化程度对数学模型效率的高低有重要的影响,这一点将在第二部分中详细阐述。
可推广性:数学模型可以推广到具有相同性质的一类问题中。换句话说,解决了一个数学模型就解决了一类实际问题。这里的“相同性质”是指相同的本质,表面看似毫不相干的问题可能有着相同的本质。由于这一点也是由数学模型的抽象性决定的,因此数学模型的抽象化程度对数学模型的推广范围也有重要的影响,这一点将在第三部分中详细阐述。
二、数学模型的建立和比较
由于考虑问题的角度不同,面对同一个实际问题,可能建立起各种各样的数学模型。在各种数学模型中,我们要寻找的是效率高的模型。模型的效率同模型的抽象化程度有关,下面从一个实例中来分析它们之间的具体关系。
【多边形分割问题】将一个凸n边形用n-3条互不相交的对角线分割为n-2个三角形,求分割方案的总数.
如:n=5时,有以下几种分割方案:
这道题可用以下几种方法来求解:
<1>.搜索法:
这种方法的思路是将各种分割方案全都列举出来。
显然,一组n-3条互不相交的对角线对应于一种分割方案,因此可把问题看作是求不同的对角线组的数目。
将n边形的n个顶点按顺时针方向编号为1、2、3……n,则一条对角线可表示为一个数对(a1,a2),a1、a2分别表示对角线两端顶点的序号,a1<a2,a1为对角线的始端,a2为末端。
对角线在对角线组中的顺序是无关紧要的,因此,一个对角线组是一个集合,它的元素是对角线。
判断两条对角线是否相交是一个必须解决的问题。设两条对角线分别为(a1,a2)与(b1,b2),若把表示对角线的数对看作开区间,那么两条对角线不相交的充要条件是两个区间有包含关系或他们的交集为空集。
于是,我们建立起解决本问题的第一个数学模型:
已知:n的值,
一个集合由(n-3)个不同的开区间(i,j)组成,
i∈{1..n-2}, j∈{i+2..n},(i≠1)或(j≠n)
同一个集合中任两个不同的开区间(i1,j1),(i2,j2)满足:
((i1,j1)∩(i2,j2)=空集)或((i1,j1)包含(i2,j2))或((i2,j2)包含(i1,j1))
求:不同的集合的个数
搜索时,先考虑以顶点1为始端的对角线,可以不连任何对角线(图一中A),也可以连(1,3)(图一中B),或连(1,4)(图一中C),或同时连(1,3)(1,4) (图一中D)。对于每一种情况,再考虑以顶点2为始端的对角线,依此类推。当得到n-3条互不相交的对角线时,便找到了一种方案(参见图一)。
图一
在考虑以顶点i为始端的对角线时,有以下几条规则必须遵循:
1.与原有对角线相交的对角线不得选取。
2.当i>=3时,若顶点i-1为始端的对角线一条都未连,则对角线(i-2,i)必须是已经连的。
3.对角线的末端顶点序号必须大于i。否则,顶点i将成为对角线的末端,另一个顶点j(j<i)成为对角线的始端,这条对角线已在考虑以顶点j为始端的对角线时考虑过了,再考虑将引起重复。
按照以上三条规则,即可得到如图一的搜索树(图中打√的叶结点为不同的分割方案)。
搜索法的数学模型较为复杂,用它可以求出具体方案,但它的抽象化程度不高,导致了求解时的低效率。为了使用上面的规则2来提高效率,求解过程还是从多边形及其对角线本身来考虑的,数学模型的作用仅体现在判断对角线是否相交上。用该方法编制的程序在n稍大时速度就很慢。(n=12时已需运行时间16.2秒(486DX2/80),测试结果见附表一。)
<2>.递推法:
上一种方法的数学模型中有很多与问题的要求无关的内容(如对角线的表示、对角线组的表示、每种具体方案)。在递推法建立的数学模型中,我们只考虑凸n边形的分割方案总数。
设k边形的分割方案总数为Ak,于是得到A数列:A3,A4,A5...
考虑n边形的分割方案总数An。任取n边形的一条边,不妨取边(n-1,n), 若在某一种分割方案中,边(n-1,n)属于三角形(i,n-1,n),那么就将分割方案归入第i类,如图二所示。
图二
设第i类方案总数为Bi,则
①
计算Bi可用如下方法:
对于第i类的方案,原n边形已被分割为一个i+1边形与一个(n-i)边形,下面的工作分为两步,第一步是将i+1边形分割为三角形,有Ai+1种方案,第二步是将(n-i)边形分割为三角形,有An-i种方案。为了表达的方便,令A2=1,于是有
②
将②代入①得:
③
于是,问题的数学模型即为:
已知:n的值及数列A2,A3,A4……,
该数列满足:
A2=1
, j>2
求:An
利用这个模型,我们即可很方便地依次求出A3,A4...An。
递推法的数学模型比搜索法的简明,抽象化程度更高,效率也高得多。用递推法编制的程序已能应付中等数据,在n<100时不超过一秒。但当n很大时仍然很慢,n=250时需18.7秒(486DX2/80),测试结果见附表一。
<3>.母函数法:
上一种方法的数学模型中已去除了很多与问题的要求无关的内容,但同时,问题只要求An,而上述方法却将A3~An都求出了。能否不求A3~An-1而直接由n求出An呢?下面用母函数这种数学模型来解决这个问题。
将A2,A3,A4……作为幂级数的系数,令
④
如果能解出Y(x),那么也就求出了An.
为了求Y(x),我们来看一下Y(x)^2的值:
而 ,因此有:
⑤
⑤-④*x得:
将 代入,解出 :
各项系数均为负数,而Ai>0,故:
⑥ ,
其中 ,
于是,
所以,
于是得出了由n直接求出An的数学模型:
已知:n的值,
⑦
求:An
求解时用公式⑦可直接计算An。
在三个数学模型中,这一个表达最为简洁,抽象化程度最高。用它来求解的效率也最高。n=1000时不超过1秒,n=5000时也仅需14.7秒(486DX2/80),测试结果见附表一与附表二。
搜索法作为一种最基本的方法,建立在一个较为复杂的数学模型之上,它的特点是可以求出每一种分割方法,但用这种方法来求方案总数显然针对性不强,因此效率很低。递推法是建立在数列这个数学模型之上的,由于去除了很多不必要的因素,效率大为提高,对于n<=300时有较好的效果。利用母函数这种数学模型求解,是对递推法的一种数学优化,得出了更为简洁的结论,当n>300时充分显示出其优势。
从以上的分析中可以得出这样的结论:数学模型的抽象化程度越高,它的效率越高。这个结论很容易理解,因为抽象化程度越高,数学模型中与问题无关的成分就越少,于是效率也就越高。相反的,若抽象化程度不够高,则数学模型中含有较多的与问题无关的成分,那么,效率也就要低一些。
三、数学模型的推广和应用
数学模型具有可推广性。
数学模型是建立在问题本质的基础上的,而不是建立在问题的表面现象上的。因此,虽然两个问题表面毫无关系,只要它们有相同的本质,就可以用相同的数学模型求解。然而,要看到两个问题有相同的本质并不是一件容易的事。这需要我们抛开问题的表面现象,仔细地比较分析,在问题之间建立对应关系。
数学模型的可推广性与数学模型的抽象化程度有着密切的关系。为解决同一个问题而建立起的不同的数学模型可能具有不同的可推广性。
下面将由母函数建立起的数学模型应用于另一些问题的求解。
【树的计数问题】求具有n个结点的二叉树的数目。
设具有k个结点的的二叉树的数目为Dk,则
* 当k=0时,是一棵空树,只有一种。
* 当k>0时,二叉树可分为根结点、具有i个结点的左子树与具有k-1-i个结点的右子树。于是具有k个结点的二叉树的数目等于具有i个结点的二叉树的数目与具有k-1-i个结点的二叉树的数目的乘积。
将以上的分析写成公式,就是:
比较上文中A数列与这里的D数列可知 ,于是将上文中的数学模型(⑦式)稍加变换,即得:
⑧
至此,我们已将这个问题用上面的数学模型解决了。这个问题与[多边形分割问题]具有相同的本质,即它们计数的规律是一致的,因此,它们可用相同的数学模型求解。
为了将这种数学模型进一步推广,我们再将上一个问题分析一下:将每棵二叉树的n个结点一一编号,使每棵二叉树的前序序列都是1,2,3…,n。由于前序序列与中序序列可唯一确定一棵二叉树,所以每棵二叉树的中序序列与其它的二叉树都是不同的。(一旦相同,那么这两棵二叉树就是同一棵二叉树了。)
另外,对于一棵前序序列确定的二叉树,它的中序序列可以由前序序列进栈与出栈生成。于是该数学模型又可直接用于下面问题的求解。
【火车进出栈问题】一列火车n节车厢,依次编号为1,2,3,…,n。每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。
将这个问题与上一个问题比较一下:列车原始的排列状态(1,2,3,…,n)正是二叉树的前序序列;列车车厢的进栈与出栈对应于二叉树结点的进栈与出栈;列车出栈后的排列状态正是二叉树的中序序列。
将两道题对应起来看,不难发现,列车出栈后的可能排列方式的数目就是二叉树的中序序列的数目,也就是二叉树的数目。
设n节车厢的排列方式有En种,则
⑨
于是,我们又用相同的数学模型解决了这个问题。
将数学模型推广到[树的计数问题]时,我们只是比较了相似的递推公式,可以说是一种简单的推广。而推广到[火车进出栈问题]时,则是从[树的计数问题]出发,将两个问题对应起来看,进行了很多逻辑分析,相比之下要复杂一些。事实上,很多数学模型的推广应用都需要进行仔细的分析。
从一个问题[多边形分割问题]出发建立起的数学模型 ,公式中已完全略去了分割的具体内容,只留下了问题的本质:计数。由于公式表达了计数方法的实质内涵( ; ),于是就给了它进一步广泛应用于一类问题求解(外延)的可能。
再考虑一下[多边形分割问题]中搜索法的数学模型。在这两个问题中,搜索法的数学模型显然是不适用的。它包含着多边形的每一种具体的分割方案,没有很好的体现问题计数的本质,因此影响了这种数学模型的可推广性。在这两个问题中,没有相应的概念对应于多边形的分割方案,于是,搜索法的数学模型便对这两个问题无能为力了。而数列与母函数两种方法的数学模型仍能应用于这两个问题。这正是由于后两种方法的数学模型更加抽象,所以更有利于它们的推广。
四、总结
以上三个实例充分说明了数学模型的高效性、可推广性以及它们与抽象性之间的关系。
数学模型具有高效性。从实际问题中建立起来的数学模型可以去除无关的内容,关系清晰,有利于效率的提高。
数学模型具有可推广性。从实际问题中建立求解的数学模型,一个数学模型建立后,往往能将其应用于一类实际问题中。乍一看[分割多边形]与[火车进出栈]没有什么联系,但通过对模型的理解可以发现两个问题有着密切的内在联系:它们是可以用相同的数学模型来求解的。
数学模型的高效性与其抽象性是紧密联系的。数学模型越是抽象,它的效率也就越高。数学模型的可推广性与其抽象性也是紧密联系的。数学模型越是抽象,它也就越容易被广泛应用。
【附件】
附表一:按以上三种数学模型设计的程序的运行时间的比较
n 运行时间(秒)(486/80) 结果
搜索法 递推法 母函数法
5 0.0 0.0 0.0 5
8 0.1 0.0 0.0 132
10 0.6 0.0 0.0 1430
11 3.2 0.0 0.0 4862
12 16.8 0.0 0.0 16796
20 0.0 0.0 477638700
30 0.1 0.0 263747951750360
40 0.1 0.0 176733862787006701400
50 0.1 0.0 131327898242169365477991900
70 0.3 0.0 86218923998960285726185640663701108500
100 0.8 0.0 57743358069601357782187700608042856334020731624756611000
150 3.1 0.0 39593131470570019928884900188787576804513637926117934749025519709205419589642069387800
200 8.3 0.1 32497017144692472040610304198911001293287035403710045969725655314584740305629299507691330189130411971857871567302000
250 18.7 0.1 29421094651142749009320132912247185432038644991268111203317168783696949400211003928295831546272022257999617419625465614367577576739594354716172000
300 37.1 0.1 28336159511286454919521412986993508946492467649011644182088598624691519032559650708037365499927532029654393447069621322187712454333678323104526897225807029224162563399190436400
附表二:母函数法在大数据下的运行时间与结果
n 运行时间
(秒,486/80) 结果
500 0.2 33921614812585475334363286760428341518066713710519482246463222890220389484961666016394087658935561710828507304323072584219401165213694125111808676743383111725525109395221667675218154975403925407900951874783446636778584625969536221341025202009861761506606387807458519527863423617862710486790680000
1000 0.6 128265912312032938999241890786456388208903205231897185061007133365865969176506365089713922696363843301311695301832064235198187588912415947083334328015864565893550987852108368101709312590228295938009433241620526247192140999561162751158086315074018026699675460282488559819788747628392613863733448076516046300459037213377768161536810646612071844252778457242818599932809910085516200019191596126573215746216258241717105949596945086725752677939963074419330042262461785897282518971742893682255505361949539216436303974544929904457402642729850569605966260001940761086095518361490603411114114203867955760000
5000 14.7 1990533983292846325166673506454278003389272904305553280180872823100271211876734085661320525800982391106168982281996605880011739654359813542758695597927784296140146907866061711715283200830450446714899249720475015233342468138724573840895739739033811420784581508456866514843728085684023096771538155357865596755677654398271755290553728036099183628752965320662495987063081218956333397309697251612668756490770219470026315305011566054014660857597536352915369221824992631352492185831978570219673534486780746350434887270380668276557335753276871786347768612211133866915304199873699266973452113841368846239215902251088131078338594137550754919249542962423635965944666671446673358771831246640688142040703856338776629977766659654255268159378975104451911736990086945769021035259522823770948943057400745943601902801641100388276960355859153873511990973753013315562935808904939180986223807552333892680521693312997068069144010511282780445912971074861274051992834639631056121645180516533443241763461820322685891901250005766673255334183011114708195338121209880104450610031605570181725548173371083940591081739155535821737987646875652182998581745666283678405193386287633644237910478216042546366880337839398239555205412965010863073403341689820527195143227554240769318197214550404929767921019476713935147688604715074128914593275201180172696786877749972031468886291116599954859230193707272332890105705243614350673513288561103329172243184327475890245902422379591116933541402407304673289273956454592243290522479908546449720240299728273313773131071960862210627650188202833681955696454854968868373243539755357093842908311125187443209114068668300881662599791538502970558610311959605119059285721310792265335734974618605961113788698323446988560897984443165154909954174602938557585213780659674972152322112734313586718289148701156895171132685679870431003809667418695642469238836695141084658775900119665937226717903862379727919631656239883098441287324447074205284653760604178405308840988804551418639124664176032592842849445923263161630959760172685607996743155249441458740184540341637246704062232001851089226650716732821068117296304334142247077033558814482032810656613007364273147899358789829435814444102740310008484918033748262914234177331202318998592244539101401954666570026383034960883253619564875198162402993935315752578275978527638007420272235699836321668787827569604597992145402860459286867814341553850087680862132619806785611873322337760485664946553533366401151012142801380925362116746164301057451528028965946453997211806286217707956621562985038678355768449118075262217561378974164882591433135421096327093683365937426849146897242720850054696490138864962273508257492244688170498625618918459291917844876832932013180312437483376087705819619480311149682354318637525937296089982305588050631890322060001728960148182457730920457465399070572366773805403226916986159594221481032617470371581495719930597851695669555189979332882416754183716357001209090944294741473972997610488038219507132437063465054808258284329237819893018092810058281353800000
【程序】
1.多边形分割问题 搜索法 (sousuo.pas)
{$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V+,X+,Y-}
{$M 16384,0,655360}
Program SouSuo;
Const
Max=30;
Type
TPara=record l,r:integer;end; {区间类型}
Var
method:Longint; {方案总数}
Para:array[1..Max]of TPara; {区间组}
n:integer;
time:Longint;
Function M(a,b:integer):integer;{高精度整数类型}
begin if a<b then m:=b else m:=a;end;
Procedure Make; {搜索多边形的所有分割方案}
Var i,j:integer;
sp,lp1,lp2:integer;
Function Connect:boolean; {判断新加入区间组的区间是否与原有的区间有冲突}
var i,j,k:integer;b1,b2:boolean;
begin
j:=para[sp].l;k:=para[sp].r;
Connect:=true;
for i:=1 to sp-1 do
begin
if (j=para[i].l)or(j=para[i].r) then continue;
if (k=para[i].l)or(k=para[i].r) then continue;
if ((j>para[i].l)and(j<para[i].r))xor
((k>para[i].l)and(k<para[i].r))
then exit;
end;
Connect:=false;
end;
Function PreFalse:boolean; {检验是否有其它的冲突}
var i:integer;j,k:integer;
begin
prefalse:=false;j:=para[sp].l;
if j<=2 then exit;
for i:=1 to sp do
if (para[i].l=j-1)or(para[i].r=j-1) then exit;
k:=j;j:=k-2;
for i:=1 to sp do
if (para[i].l=j)and(para[i].r=k) then exit;
PreFalse:=true;
end;
Function Pop:boolean;forward;
Function Push:boolean; {入栈}
begin
inc(sp);
Para[sp].l:=lp1;Para[sp].r:=lp2;
Push:=((lp1=1)and(lp2=n))or(lp1>n)or(lp2>n)or connect;
if prefalse then
begin Push:=true;pop;exit;end;
inc(lp2);
if lp2>n then
begin inc(lp1);lp2:=lp1+2;end;
end;
Function Pop:boolean; {出栈}
begin
if sp=0 then
begin dec(sp);pop:=false;exit;end;
lp1:=Para[sp].l;lp2:=para[sp].r;dec(sp);
inc(lp2);
if lp2>n then
begin inc(lp1);lp2:=lp1+2;end;
Pop:=(lp1>n)or(lp2>n);
end;
begin
sp:=0; {栈顶指针置0}
lp1:=1;lp2:=3;
method:=0;
while (sp>=0) do
begin
if Push then while pop do;
if sp=n-3 then {获得了一种方案}
begin
method:=method+1;
while pop do;
end;
end;
writeln('Total: ',method);
end;
var i:integer;s:string;
BEGIN
write('Input N: ');
readln(n);{输入多边形边数}
time:=MemL[$40:$6c];
if n<3 then writeln('Total: 0')
else if n=3 then writeln('Total: 1')
else MAKE; {搜索多边形的所有分割方案}
writeln('Time: ',(Meml[$40:$6c]-time)/18.2:5:1);
{输出所用的时间}
END.
2.多边形分割问题 递推法 (ditui.pas)
{$A+,B-,D-,E-,F-,G+,I-,L-,N+,O-,P-,Q-,R-,S-,T-,V+,X+,Y-}
{$M 16384,0,655360}
Program DiTui;
Const
Len=100;Max=300;
Type
Th=array[-1..Len+1]of integer;{高精度整数类型}
Var
method:array[1..Max]of Th; {i边形分割方案总数为method[i]}
n:integer; {要求的多边形的边数}
time:Longint;
Function M(a,b:integer):integer; {取最大值}
begin if a<b then m:=b else m:=a;end;
Procedure Add(var a:Th;b:Th); {a:=a+b;a,b为高精度整数类型}
var i,j:integer;
begin
j:=0;
a[-1]:=m(a[-1],b[-1]);
for i:=0 to a[-1] do
begin inc(j,a[i]+b[i]);
a[i]:=j mod 10000; {每位integer存4位十进制数}
j:=j div 10000;
end;
if j<>0 then
begin inc(a[-1]);a[a[-1]]:=j;end;
end;
Procedure Mul(a,b:Th;var c:Th); {c:=a*b;a,b,c为高精度整数类型}
var i,j:integer;k:Longint;
begin
fillchar(c,sizeof(Th),0);
for i:=0 to a[-1] do
begin
k:=0;
for j:=0 to b[-1] do
if i+j<=Len then
begin
inc(k,longint(a[i])*b[j]+c[i+j]);
c[i+j]:=k mod 10000;
k:=k div 10000;
end;
inc(c[i+b[-1]+1],k);
end;
c[-1]:=a[-1]+b[-1];
if c[c[-1]+1]<>0 then inc(c[-1]);
end;
Procedure OutHigh(a:Th); {输出高精度整数}
var s:string[4];i,j:integer;
begin
write('Total: ');
j:=a[-1];write(a[j]);
for i:=j-1 downto 0 do
begin
str(a[i],s);while s[0]<#4 do s:='0'+s;
write(s);
end;
writeln;
end;
Procedure Make; {递推计算多边形分割总数}
var i,j:integer;a:Th;
begin
fillchar(method,sizeof(method),0);
method[2,0]:=1;
method[3,0]:=1;
fillchar(a,sizeof(a),0);
for i:=4 to N do
for j:=1 to i-2 do
begin
mul(method[j+1],method[i-j],a);
Add(method[i],a);
end;
OutHigh(method[n]);
end;
var i:integer;s:string;
BEGIN
write('Input N: ');
readln(n); {输入多边形边数}
time:=MemL[$40:$6c];
if n<3 then writeln('Total: 0')
else MAKE;{递推计算多边形分割总数}
writeln('Time: ',(Meml[$40:$6c]-time)/18.2:5:1);
{输出所用的时间}
END.
3.多边形分割问题 母函数法 见muhanshu.Pas
{$A+,B-,D-,E-,F-,G+,I-,L-,N+,O-,P-,Q-,R-,S-,T-,V+,X+,Y-}
{$M 16384,0,655360}
Program MuHanShu;
Const
Len=1400;Max=6000;
Type
Th=array[0..Len+1]of integer;{高精度整数类型1,按位存储}
Ty=array[0..Max]of integer;{高精度整数类型2,按因数存储}
Var
fi,fo:text;fin,fon:string;
n:integer;
time:Longint;
Procedure Mul(var a:Th;b:integer); {a:=a*b;a为高精度整数类型1}
Var i:integer;k:Longint;
begin
k:=0;
for i:=1 to a[0] do
begin
k:=k+a[i]*longint(b);
a[i]:=k mod 10000;
k:=k div 10000;
end;
if k<>0 then
begin inc(a[0]);a[a[0]]:=k;end;
end;
Function MaxPublic(a,b:integer):integer; {a,b的最大公因数}
var i:integer;
begin
repeat
a:=a mod b;
if a=0 then break;
b:=b mod a;
until b=0;
MaxPublic:=a+b;
end;
Procedure Divide(var k:Ty;h:integer);{k:=k div h;k为高精度整数类型2}
Var i,j:integer;
begin
for i:=1 to k[0] do
if k[i] mod h =0 then
begin k[i]:=k[i] div h;
if k[i]=1 then begin k[i]:=k[k[0]];dec(k[0]);end;
exit;
end;
for i:=k[0] downto 1 do
if MaxPublic(k[i],h)>1 then
begin
j:=MaxPublic(k[i],h);
h:=h div j;k[i]:=k[i] div j;
if k[i]=1 then begin k[i]:=k[k[0]];dec(k[0]);end;
if h=1 then exit;
end;
end;
Procedure translate(k:Ty;var a:Th);{a:=k;a为高精度整数类型1,k为高精度整数类型2}
Var i:integer;
begin
a[1]:=1;a[0]:=1;
for i:=1 to k[0] do mul(a,k[i]);
end;
Procedure Make;{按公式计算多边形分割总数}
Var i,j:integer;k:Ty;a:Th;s:string[4];
begin
k[0]:=n-2;
for i:=1 to n-2 do k[i]:=(2*n-3-i);
for i:=n-2 downto 2 do divide(k,i);
divide(k,n-1);
translate(k,a);
write('Total: ');
j:=a[0];write(a[j]);
for i:=j-1 downto 1 do
begin
str(a[i],s);while s[0]<#4 do s:='0'+s;
write(s);
end;
writeln;
end;
var i:integer;s:string;
BEGIN
write('Input N(<=',Max,'): ');
readln(n); {输入多边形边数}
time:=MemL[$40:$6c];
if n<3 then writeln('Total: 0')
else MAKE; {按公式计算多边形分割总数}
writeln('Time: ',(Meml[$40:$6c]-time)/18.2:5:1);
{输出所用的时间}
END.
4.树的计数问题、火车进出栈问题 (tuiguang.pas)
{$A+,B-,D-,E-,F-,G+,I-,L-,N+,O-,P-,Q-,R-,S-,T-,V+,X+,Y-}
{$M 16384,0,655360}
Program TuiGuang;
Const
Len=1400;Max=5002;
Type
Th=array[0..Len+1]of integer;{高精度整数类型1,按位存储}
Ty=array[0..Max]of integer;{高精度整数类型2,按因数存储}
Var
fi,fo:text;fin,fon:string;
n:integer;
time:Longint;
Procedure Mul(var a:Th;b:integer); {a:=a*b;a为高精度整数类型1}
Var i:integer;k:Longint;
begin
k:=0;
for i:=1 to a[0] do
begin
k:=k+a[i]*longint(b);
a[i]:=k mod 10000;
k:=k div 10000;
end;
if k<>0 then
begin inc(a[0]);a[a[0]]:=k;end;
end;
Function MaxPublic(a,b:integer):integer; {a,b的最大公因数}
var i:integer;
begin
repeat
a:=a mod b;
if a=0 then break;
b:=b mod a;
until b=0;
MaxPublic:=a+b;
end;
Procedure Divide(var k:Ty;h:integer);{k:=k div h;k为高精度整数类型2}
Var i,j:integer;
begin
for i:=1 to k[0] do
if k[i] mod h =0 then
begin k[i]:=k[i] div h;
if k[i]=1 then begin k[i]:=k[k[0]];dec(k[0]);end;
exit;
end;
for i:=k[0] downto 1 do
if MaxPublic(k[i],h)>1 then
begin
j:=MaxPublic(k[i],h);
h:=h div j;k[i]:=k[i] div j;
if k[i]=1 then begin k[i]:=k[k[0]];dec(k[0]);end;
if h=1 then exit;
end;
end;
Procedure translate(k:Ty;var a:Th);{a:=k;a为高精度整数类型1,k为高精度整数类型2}
Var i:integer;
begin
a[1]:=1;a[0]:=1;
for i:=1 to k[0] do mul(a,k[i]);
end;
Procedure Make;{按公式计算}
Var i,j:integer;k:Ty;a:Th;s:string[4];
begin
k[0]:=n-2;
for i:=1 to n-2 do k[i]:=(2*n-3-i);
for i:=n-2 downto 2 do divide(k,i);
divide(k,n-1);
translate(k,a);
write('Total: ');
j:=a[0];write(a[j]);
for i:=j-1 downto 1 do
begin
str(a[i],s);while s[0]<#4 do s:='0'+s;
write(s);
end;
writeln;
end;
var i:integer;s:string;
BEGIN
write('Input N(<=',Max-2,'): ');
readln(n); {输入N}
inc(n,2);
time:=MemL[$40:$6c];
MAKE; {按公式计算}
writeln('Time: ',(Meml[$40:$6c]-time)/18.2:5:1);
{输出所用的时间}
END.
【参考书目】
《信息学奥林匹克》1998.1-2 中国计算机学会普及工作委员会、TSINGHUA UNIVERSITY ACM STUDENT CHAPTER 主办,第87页、第93-94页;
《数据结构》(第二版),严蔚敏、吴伟民编著,清华大学出版社1992年6月,第150-154页;
《中学生数学建模读本》,孔凡海编著,江苏教育出版社 1998年1月。