区间DP——凸多边形的三角形划分

本文探讨了如何将一个凸多边形通过最优方式划分成多个三角形的问题,旨在找到顶点权重乘积之和最小的方案。文章提供了一种算法实现,并详细解释了其背后的原理,包括使用高精度计算来处理可能的大数值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题 C: 凸多边形的三角形划分

时间限制: 1 Sec  内存限制: 128 MB
提交: 4  解决: 2
[提交][状态][讨论版][命题人:add_oopscyc]

题目描述

给定一具有N个顶点(从1到N编号)的凸多边形,每个顶点的权均已知。问如何把这个凸多边形划分成N-2个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小?

输入

第一行 顶点数N(N<50)。
第二行 N个顶点(从1到N)的权值,权值为小于32768的整数。

 

输出

各三角形顶点的权的乘积之和最小值。

样例输入

5
121 122 123 245 231

样例输出

12214884
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
int n,j;
long long int f[110][110][110],a[110],s1[110],s2[110],s3[110];
void mark(long long int c[])//高精度处理
{
    for(int i=1;i<=c[0];i++)
    {
        c[i+1]+=c[i]/10000;
        c[i]%=10000;
    }
    while(c[c[0]+1])
    {
        c[0]++;
        c[c[0]+1]+=c[c[0]]/10000;
        c[c[0]]%=10000;
    }
}
void mul(long long int a1,long long int a2,long long int a3,long long int c[])
//将a1*a2*a3的值存储在数组c中,高精度乘法
{
    c[0]=c[1]=1;
    for(int i=1;i<=c[0];i++)
        c[i]*=a1;
    mark(c);
    for(int i=1;i<=c[0];i++)
        c[i]*=a2;
    mark(c);
    for(int i=1;i<=c[0];i++)
        c[i]*=a3;
    mark(c);
}
void add(long long int a[],long long int b[],long long int c[])
//高精度加法
{
    c[0]=max(a[0],b[0]);
    for(int i=1;i<=c[0];i++)
        c[i]=a[i]+b[i];
    mark(c);
}
int compare(long long int a[],long long int b[])
{
    if(a[0]<b[0])
        return 0;
    if(a[0]>b[0])
        return 1;
    for(int i=a[0];i>=1;i--)
        if(a[i]<b[i])return 0;
        else if(a[i]>b[i])return 1;
    return 0;
}
void print()//输出答案
{
    cout<<f[1][n][f[1][n][0]];
    for(int i=f[1][n][0]-1;i>=1;i--)
    {
        cout<<f[1][n][i]/1000;
        cout<<f[1][n][i]/100%10;
        cout<<f[1][n][i]/10%10;
        cout<<f[1][n][i]%10;
    }
    cout<<endl;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        f[i][j][0]=0;//初始化
    for(int num=2;num<=n-1;num++)//划分次数
        for(int i=1;i<=n-num;i++)//起点
        {
            j=i+num;//终点
            f[i][j][0]=60;
            for(int k=i+1;k<=j-1;k++)
            {
                memset(s1,0,sizeof(s1));
                memset(s2,0,sizeof(s2));
                memset(s3,0,sizeof(s3));
                mul(a[i],a[k],a[j],s1);//将三角形顶点权值相乘,s1=a[i]*a[k]*a[j]
                add(f[i][k],f[k][j],s2);//s2=f[i][k]+f[k][j]
                add(s1,s2,s3);//s3=s1+s2=a[i]*a[k]*a[j]+f[i][k]+f[k][j]
                if(compare(f[i][j],s3))
                    memcpy(f[i][j],s3,sizeof(s3));//f[i][j]=min(f[i][j],s3),求最小值
            }
        }
    print();//输出答案
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值