问题:给定凸n边形P={1,2…,n},每一个顶点i带一个权数r(i)(i=1,2,…,n)。要求在该凸边形的顶点间连n-3条互不相交的连线,把凸边形分成n-2个三角形,每一个三角形的值为其他三个顶点权数之和。
解决过程:
(1)建立递推关系:
设m(i,j)是求多边形MiMi+1…Mj划分的最小值,则有递推关系:
m(i,i+2)=r(i)r(i+1)r(i+2)(j=i+2时,即三角形MiMi+1Mi+2)
m(i,j)=min(m(i,k)+m(k,j)+r(i)r(k)r(j)(i<k<j)
初始(边界)条件为m(i,i+1)=0(不构成三角形)
显然,m(1,n)为最优值。
(2)求最优值的递推结构:
当i<k<j且要求m(i,j)时,要用到m(i,k)和m(k,j)。为此,设置以下循环:
for(d=2;d<=n-1;d++)
for(i=1;i<=n-d;i++)
j=i+d;
这样,可按d从2开始递增取值,先得m(i,k)与m(k,j),为比较进而求m(i,j)提供可能。
(3)构造最优解
设置s(i,j),在递推赋值时记录最优划分点k。注意到分划线分布为二叉结构,应用s(i,j)定义实现最优解的递归函数 f(a,b):
a:设置c=s(a,b)记录参数a和b的最优分化点。
b:若c>a+1,则输出a~c;
c:若c<b-1,则输出c~b;
d:然后调用下一层递归函数f(a,c)和f(c,b)。
#include<stdio.h> int p,s[100][100]; main() { int d,n,i,j,k,r[100]; long t,m[100][100]; void f(int x,int y); printf(" 请输入n:"); scanf("%d",&n); printf(" 凸%d边形从第一点开始,依次输入各点权数:\n",n); for(i=1;i<=n;i++) { printf(" 请输入第%d个顶点的权数:",i); scanf("%d",&r[i]); } for(i=1;i<=n-1;i++) m[i][i+1]=0; for(d=2;d<=n-1;d++) for(i=1;i<=n-d;i++) { j=i+d; m[i][j]=100000000; for(k=i+1;k<j;k++) { t=m[i][k]+m[k][j]+r[i]*r[k]*r[j]; if(t<m[i][j]) { m[i][j]=t; s[i][j]=k; } } } p=0; printf("\n 最优%d条划分线分别为:\n",n-3); f(1,n); printf("\n 凸%d边形的三角形划分最小值为:%ld \n",n,m[1][n]); }
#include<stdio.h>
void f(int a,int b)
{
int c;
if(b>a+1)
{
c=s[a][b];
if(c>a+1)
{
p++;
printf(" %2d--%2d;",a,c);
if(p%6==0) printf("\n");
}
if(c<b-1)
{
p++;
printf(" %2d--%2d;",c,b);
if(p%6==0) printf("\n");
}
f(a,c);f(c,b);
}
return;
}