Acwing 1069. 凸多边形的划分(区间DP)

解题思路:给定我们一个凸多边形,首先我们要知道如何对这个多边形进行划分,我们可以选择的两个点,然后在这两个点之间再选择一个点,这样就构成了一个三角形,这样就把这个凸多边形分成了2个多边形和一个三角形,因为分成的两个多边形之间没有联系,所以这是我们用区间DP来做这道题的基础,我们假设出数组f[i][j]表示从第i个顶点到第j个顶点构成的多边形通过划分得到的所有三角形顶点权值乘积之和的最小值,那么它可以由谁来得到呢?设置中间变量k,i<k<j,选择i,j,k三个点构成一个三角形,并将整个大多边形分割成了一个三角形和两个小凸多边形,而小凸多边形我们可以用相同的方法来解决,所以得到递推方程:f[i][j]=min(f[i][k]+f[k][j]+w[i]*w[j]*w[k]),i<k<j,我们要从规模小的问题一步一步向大规模问题来递推,所以设置变量len来控制问题的规模,因为规模最小就是只有一个三角形,所以len可以从3开始取,分析到这里其实不难发现就是一个区间DP问题的小变形,再看数据量,我们会惊奇地发现数据会爆long long ,所以对于中间过程中数据的计算要用到高精度,其实我感觉这个题的考察重点就是用高精度来求解,思路并不难,上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=110;
const int M=35;
int w[N];
long long f[N][N][M];
int n;
void add(long long a[],long long b[])
{
    long long c[M];
    memset(c,0,sizeof c);
    int t=0;
    for(int i=0;i<M;i++)
    {
        t+=a[i]+b[i];
        c[i]=t%10;
        t/=10;
    }
    memcpy(a,c,sizeof c);
}
void mul(long long a[],long long b)
{
    long long c[M];
    memset(c,0,sizeof c);
    long long t=0;
    for(int i=0;i<M;i++)
    {
        t+=a[i]*b;
        c[i]=t%10;
        t/=10;  
    }
    memcpy(a,c,sizeof c);
}
int cmp(long long a[],long long b[])
{   
    for(int i=M-1;i>=0;i--)
    if(a[i]>b[i])
    return 1;
    else if(a[i]<b[i])
    return -1;
    return 0;
 
}
void print(long long a[])
{
    int k=M-1;
    while(k>=0&&a[k]==0)
    k--;
    while(k>=0)
    cout<<a[k],k--;
    cout<<endl;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    cin>>w[i];
    long long temp[M];
    for(int len=3;len<=n;len++)
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1;
            f[i][j][M-1]=1;//把初始的数组设成一个比较大的数
                for(int k=i+1;k<j;k++)
                {
                    memset(temp,0,sizeof temp);
                    temp[0]=w[i];
                    mul(temp,w[k]);
                    mul(temp,w[j]);
                    
                    add(temp,f[i][k]);
                    add(temp,f[k][j]);
                    if(cmp(f[i][j],temp)>0)
                    memcpy(f[i][j],temp,sizeof temp);
                }
        }   
    print(f[1][n]);
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值